1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.squareup.okhttp.internal.http; 18 19 import com.squareup.okhttp.internal.spdy.SpdyConnection; 20 import com.squareup.okhttp.internal.spdy.SpdyStream; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.io.OutputStream; 24 import java.net.CacheRequest; 25 import java.net.URL; 26 import java.util.List; 27 28 public final class SpdyTransport implements Transport { 29 private final HttpEngine httpEngine; 30 private final SpdyConnection spdyConnection; 31 private SpdyStream stream; 32 33 public SpdyTransport(HttpEngine httpEngine, SpdyConnection spdyConnection) { 34 this.httpEngine = httpEngine; 35 this.spdyConnection = spdyConnection; 36 } 37 38 @Override public OutputStream createRequestBody() throws IOException { 39 // TODO: if we aren't streaming up to the server, we should buffer the whole request 40 writeRequestHeaders(); 41 return stream.getOutputStream(); 42 } 43 44 @Override public void writeRequestHeaders() throws IOException { 45 if (stream != null) { 46 return; 47 } 48 httpEngine.writingRequestHeaders(); 49 RawHeaders requestHeaders = httpEngine.requestHeaders.getHeaders(); 50 String version = httpEngine.connection.getHttpMinorVersion() == 1 ? "HTTP/1.1" : "HTTP/1.0"; 51 URL url = httpEngine.policy.getURL(); 52 requestHeaders.addSpdyRequestHeaders(httpEngine.method, HttpEngine.requestPath(url), version, 53 HttpEngine.getOriginAddress(url), httpEngine.uri.getScheme()); 54 boolean hasRequestBody = httpEngine.hasRequestBody(); 55 boolean hasResponseBody = true; 56 stream = spdyConnection.newStream(requestHeaders.toNameValueBlock(), hasRequestBody, 57 hasResponseBody); 58 stream.setReadTimeout(httpEngine.policy.getReadTimeout()); 59 } 60 61 @Override public void writeRequestBody(RetryableOutputStream requestBody) throws IOException { 62 throw new UnsupportedOperationException(); 63 } 64 65 @Override public void flushRequest() throws IOException { 66 stream.getOutputStream().close(); 67 } 68 69 @Override public ResponseHeaders readResponseHeaders() throws IOException { 70 List<String> nameValueBlock = stream.getResponseHeaders(); 71 RawHeaders rawHeaders = RawHeaders.fromNameValueBlock(nameValueBlock); 72 rawHeaders.computeResponseStatusLineFromSpdyHeaders(); 73 httpEngine.receiveHeaders(rawHeaders); 74 return new ResponseHeaders(httpEngine.uri, rawHeaders); 75 } 76 77 @Override public InputStream getTransferStream(CacheRequest cacheRequest) throws IOException { 78 return new UnknownLengthHttpInputStream(stream.getInputStream(), cacheRequest, httpEngine); 79 } 80 81 @Override public boolean makeReusable(boolean streamCancelled, OutputStream requestBodyOut, 82 InputStream responseBodyIn) { 83 if (streamCancelled) { 84 if (stream != null) { 85 stream.closeLater(SpdyStream.RST_CANCEL); 86 return true; 87 } else { 88 // If stream is null, it either means that writeRequestHeaders wasn't called 89 // or that SpdyConnection#newStream threw an IOEXception. In both cases there's 90 // nothing to do here and this stream can't be reused. 91 return false; 92 } 93 } 94 return true; 95 } 96 } 97