@Override public void writeTo(BufferedSink sink) throws IOException { Source source = null; if (this.file != null) { source = Okio.source(this.file); } else if (this.data != null) { source = Okio.source(new ByteArrayInputStream(this.data)); } else if (this.inputStream != null) { source = Okio.source(this.inputStream); } long total = 0; long read, toRead, remain; while (total < contentLength) { remain = contentLength - total; toRead = Math.min(remain, SEGMENT_SIZE); read = source.read(sink.buffer(), toRead); if (read == -1) { break; } total += read; sink.flush(); if (callback != null) { callback.onProgress(MNSRequestTask.this.context.getRequest(), total, contentLength); } } if (source != null) { source.close(); } }
private Schema loadFromDirectories(List<Path> directories) throws IOException { final Deque<String> protos = new ArrayDeque<>(this.protos); if (protos.isEmpty()) { for (final Path directory : directories) { Files.walkFileTree( directory, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { protos.add(directory.relativize(file).toString()); return FileVisitResult.CONTINUE; } }); } } Map<String, ProtoFile> loaded = new LinkedHashMap<>(); while (!protos.isEmpty()) { String proto = protos.removeFirst(); if (loaded.containsKey(proto)) { continue; } ProtoFileElement element = null; for (Path directory : directories) { Source source = source(proto, directory); if (source == null) { continue; } try { Location location = Location.get(directory.toString(), proto); String data = Okio.buffer(source).readUtf8(); element = ProtoParser.parse(location, data); } catch (IOException e) { throw new IOException("Failed to load " + proto + " from " + directory, e); } finally { source.close(); } } if (element == null) { throw new FileNotFoundException("Failed to locate " + proto + " in " + sources); } ProtoFile protoFile = ProtoFile.get(element); loaded.put(proto, protoFile); // Queue dependencies to be loaded. for (String importPath : element.imports()) { protos.addLast(importPath); } } return new Linker(loaded.values()).link(); }
@Test public void readSendsWindowUpdateHttp2() throws Exception { peer.setVariantAndClient(HTTP_2, false); int windowSize = 100; int windowUpdateThreshold = 50; // Write the mocking script. peer.acceptFrame(); // SYN_STREAM peer.sendFrame().synReply(false, 3, headerEntries("a", "android")); for (int i = 0; i < 3; i++) { // Send frames of summing to size 50, which is windowUpdateThreshold. peer.sendFrame().data(false, 3, data(24), 24); peer.sendFrame().data(false, 3, data(25), 25); peer.sendFrame().data(false, 3, data(1), 1); peer.acceptFrame(); // connection WINDOW UPDATE peer.acceptFrame(); // stream WINDOW UPDATE } peer.sendFrame().data(true, 3, data(0), 0); peer.play(); // Play it back. FramedConnection connection = connection(peer, HTTP_2); connection.okHttpSettings.set(INITIAL_WINDOW_SIZE, 0, windowSize); FramedStream stream = connection.newStream(headerEntries("b", "banana"), false, true); assertEquals(0, stream.unacknowledgedBytesRead); assertEquals(headerEntries("a", "android"), stream.getResponseHeaders()); Source in = stream.getSource(); Buffer buffer = new Buffer(); buffer.writeAll(in); assertEquals(-1, in.read(buffer, 1)); assertEquals(150, buffer.size()); MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_HEADERS, synStream.type); for (int i = 0; i < 3; i++) { List<Integer> windowUpdateStreamIds = new ArrayList<>(2); for (int j = 0; j < 2; j++) { MockSpdyPeer.InFrame windowUpdate = peer.takeFrame(); assertEquals(TYPE_WINDOW_UPDATE, windowUpdate.type); windowUpdateStreamIds.add(windowUpdate.streamId); assertEquals(windowUpdateThreshold, windowUpdate.windowSizeIncrement); } assertTrue(windowUpdateStreamIds.contains(0)); // connection assertTrue(windowUpdateStreamIds.contains(3)); // stream } }
/** * Reads an entry from an input stream. A typical entry looks like this: * * <pre>{@code * http://google.com/foo * GET * 2 * Accept-Language: fr-CA * Accept-Charset: UTF-8 * HTTP/1.1 200 OK * 3 * Content-Type: image/png * Content-Length: 100 * Cache-Control: max-age=600 * }</pre> * * <p>A typical HTTPS file looks like this: * * <pre>{@code * https://google.com/foo * GET * 2 * Accept-Language: fr-CA * Accept-Charset: UTF-8 * HTTP/1.1 200 OK * 3 * Content-Type: image/png * Content-Length: 100 * Cache-Control: max-age=600 * * AES_256_WITH_MD5 * 2 * base64-encoded peerCertificate[0] * base64-encoded peerCertificate[1] * -1 * }</pre> * * The file is newline separated. The first two lines are the URL and the request method. Next * is the number of HTTP Vary request header lines, followed by those lines. * * <p>Next is the response status line, followed by the number of HTTP response header lines, * followed by those lines. * * <p>HTTPS responses also contain SSL session information. This begins with a blank line, and * then a line containing the cipher suite. Next is the length of the peer certificate chain. * These certificates are base64-encoded and appear each on their own line. The next line * contains the length of the local certificate chain. These certificates are also * base64-encoded and appear each on their own line. A length of -1 is used to encode a null * array. */ public Entry(Source in) throws IOException { try { BufferedSource source = Okio.buffer(in); url = source.readUtf8LineStrict(); requestMethod = source.readUtf8LineStrict(); if (readInt(source) == 1) { MediaType contentType = MediaType.parse(source.readUtf8LineStrict()); int contentLength = readInt(source); requestBody = RequestBody.create(contentType, source.readByteArray(contentLength)); } else { requestBody = null; } Headers.Builder varyHeadersBuilder = new Headers.Builder(); int varyRequestHeaderLineCount = readInt(source); for (int i = 0; i < varyRequestHeaderLineCount; i++) { OkHttpAccess.addLenient(varyHeadersBuilder, source.readUtf8LineStrict()); } varyHeaders = varyHeadersBuilder.build(); StatusLine statusLine = StatusLine.parse(source.readUtf8LineStrict()); protocol = statusLine.protocol; code = statusLine.code; message = statusLine.message; Headers.Builder responseHeadersBuilder = new Headers.Builder(); int responseHeaderLineCount = readInt(source); for (int i = 0; i < responseHeaderLineCount; i++) { OkHttpAccess.addLenient(responseHeadersBuilder, source.readUtf8LineStrict()); } responseHeaders = responseHeadersBuilder.build(); if (isHttps()) { String blank = source.readUtf8LineStrict(); if (blank.length() > 0) { throw new IOException("expected \"\" but was \"" + blank + "\""); } String cipherSuite = source.readUtf8LineStrict(); List<Certificate> peerCertificates = readCertificateList(source); List<Certificate> localCertificates = readCertificateList(source); handshake = Handshake.get(cipherSuite, peerCertificates, localCertificates); } else { handshake = null; } } finally { in.close(); } }
/** * Reads until {@code in} is exhausted or the deadline has been reached. This is careful to not * extend the deadline if one exists already. */ public static boolean skipAll(Source source, int duration, TimeUnit timeUnit) throws IOException { long now = System.nanoTime(); long originalDuration = source.timeout().hasDeadline() ? source.timeout().deadlineNanoTime() - now : Long.MAX_VALUE; source.timeout().deadlineNanoTime(now + Math.min(originalDuration, timeUnit.toNanos(duration))); try { Buffer skipBuffer = new Buffer(); while (source.read(skipBuffer, 2048) != -1) { skipBuffer.clear(); } return true; // Success! The source has been exhausted. } catch (InterruptedIOException e) { return false; // We ran out of time before exhausting the source. } finally { if (originalDuration == Long.MAX_VALUE) { source.timeout().clearDeadline(); } else { source.timeout().deadlineNanoTime(now + originalDuration); } } }