Browse Source

protoc-gen-grpc-swift: FileHandle for stdin, stdout (#1361)

This fixes a case where the output response is silently truncated.
Truncation occurs because the `write` syscall is only invoked a single
time, but `write` may return a value indicating a partial write for
various reasons, even in a blocking call. For example, if stdout is a
nonblocking pipe, output is truncated when the pipe is full.

Instead of rewriting Stdout.write to handle this case, let's migrate to
FileHandle for I/O, available as of Swift 3.2.

swift-protobuf has already migrated, and this commit is mostly a port of
github.com/apple/swift-protobuf/commit/2ccad3484e06d180af3bd7be53c96d41e8f03a62
Luke Rewega 4 years ago
parent
commit
59996949fa
2 changed files with 2 additions and 66 deletions
  1. 0 64
      Sources/protoc-gen-grpc-swift/io.swift
  2. 2 2
      Sources/protoc-gen-grpc-swift/main.swift

+ 0 - 64
Sources/protoc-gen-grpc-swift/io.swift

@@ -1,64 +0,0 @@
-/*
- * Copyright 2017, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import Foundation
-
-// The I/O code below is derived from Apple's swift-protobuf project.
-// https://github.com/apple/swift-protobuf
-// BEGIN swift-protobuf derivation
-
-#if os(Linux)
-import Glibc
-#else
-import Darwin.C
-#endif
-
-enum PluginError: Error {
-  /// Raised for any errors reading the input
-  case readFailure
-}
-
-// Alias clib's write() so Stdout.write(bytes:) can call it.
-private let _write = write
-
-class Stdin {
-  static func readall() throws -> Data {
-    let fd: Int32 = 0
-    let buffSize = 32
-    var buff = [UInt8]()
-    while true {
-      var fragment = [UInt8](repeating: 0, count: buffSize)
-      let count = read(fd, &fragment, buffSize)
-      if count < 0 {
-        throw PluginError.readFailure
-      }
-      if count < buffSize {
-        buff += fragment[0 ..< count]
-        return Data(buff)
-      }
-      buff += fragment
-    }
-  }
-}
-
-class Stdout {
-  static func write(bytes: Data) {
-    bytes.withUnsafeBytes { (p: UnsafeRawBufferPointer) -> Void in
-      _ = _write(1, p.baseAddress, p.count)
-    }
-  }
-}
-
-// END swift-protobuf derivation

+ 2 - 2
Sources/protoc-gen-grpc-swift/main.swift

@@ -110,7 +110,7 @@ func main() throws {
   )
 
   // read plugin input
-  let rawRequest = try Stdin.readall()
+  let rawRequest = FileHandle.standardInput.readDataToEndOfFile()
   let request = try Google_Protobuf_Compiler_CodeGeneratorRequest(serializedData: rawRequest)
 
   let options = try GeneratorOptions(parameter: request.parameter)
@@ -137,7 +137,7 @@ func main() throws {
 
   // return everything to the caller
   let serializedResponse = try response.serializedData()
-  Stdout.write(bytes: serializedResponse)
+  FileHandle.standardOutput.write(serializedResponse)
 }
 
 do {