< prev index next >

src/java.httpclient/share/classes/java/net/http/Http1Request.java

Print this page




  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  */
  24 package java.net.http;
  25 
  26 import java.io.IOException;
  27 import java.net.URI;
  28 import java.nio.ByteBuffer;
  29 import java.util.List;
  30 import java.util.Map;
  31 import java.util.Set;
  32 import java.net.InetSocketAddress;

  33 import java.nio.charset.StandardCharsets;
  34 import java.util.function.LongConsumer;
  35 import static java.nio.charset.StandardCharsets.US_ASCII;
  36 
  37 /**
  38  *  A HTTP/1.1 request.
  39  *
  40  * send() -> Writes the request + body to the given channel, in one blocking
  41  * operation.
  42  */
  43 class Http1Request {
  44 
  45     final HttpRequestImpl request;
  46     final HttpConnection chan;
  47     // Multiple buffers are used to hold different parts of request
  48     // See line 206 and below for description
  49     final ByteBuffer[] buffers;
  50     final HttpRequest.BodyProcessor requestProc;
  51     final HttpHeadersImpl userHeaders, systemHeaders;

  52     final LongConsumer flowController;
  53     boolean streaming;
  54     long contentLength;
  55 
  56     Http1Request(HttpRequestImpl request, HttpConnection connection)
  57         throws IOException
  58     {
  59         this.request = request;
  60         this.chan = connection;
  61         buffers = new ByteBuffer[5]; // TODO: check
  62         this.requestProc = request.requestProcessor();
  63         this.userHeaders = request.getUserHeaders();
  64         this.systemHeaders = request.getSystemHeaders();
  65         this.flowController = this::dummy;
  66     }
  67 
  68     private void logHeaders() throws IOException {
  69         StringBuilder sb = new StringBuilder(256);
  70         sb.append("REQUEST HEADERS:\r\n");
  71         collectHeaders1(sb, request, systemHeaders);


  74     }
  75 
  76     private void dummy(long x) {
  77         // not used in this class
  78     }
  79 
  80     private void collectHeaders0() throws IOException {
  81         if (Log.headers()) {
  82             logHeaders();
  83         }
  84         StringBuilder sb = new StringBuilder(256);
  85         collectHeaders1(sb, request, systemHeaders);
  86         collectHeaders1(sb, request, userHeaders);
  87         sb.append("\r\n");
  88         String headers = sb.toString();
  89         buffers[1] = ByteBuffer.wrap(headers.getBytes(StandardCharsets.US_ASCII));
  90     }
  91 
  92     private void collectHeaders1(StringBuilder sb,
  93                                  HttpRequestImpl request,
  94                                  HttpHeadersImpl headers)
  95         throws IOException
  96     {
  97         Map<String,List<String>> h = headers.directMap();
  98         Set<Map.Entry<String,List<String>>> entries = h.entrySet();
  99 
 100         for (Map.Entry<String,List<String>> entry : entries) {
 101             String key = entry.getKey();
 102             sb.append(key).append(": ");
 103             List<String> values = entry.getValue();
 104             int num = values.size();
 105             for (String value : values) {
 106                 sb.append(value);
 107                 if (--num > 0) {
 108                     sb.append(',');
 109                 }
 110             }
 111             sb.append("\r\n");
 112         }
 113     }
 114 
 115     private static final int BUFSIZE = 64 * 1024; // TODO: configurable?
 116 
 117     private String getPathAndQuery(URI uri) {
 118         String path = uri.getPath();
 119         String query = uri.getQuery();
 120         if (path == null || path.equals("")) {
 121             path = "/";
 122         }
 123         if (query == null) {
 124             query = "";
 125         }
 126         if (query.equals("")) {
 127             return path;
 128         } else {
 129             return path + "?" + query;
 130         }
 131     }
 132 
 133     private String authorityString(InetSocketAddress addr) {
 134         return addr.getHostString() + ":" + addr.getPort();
 135     }
 136 



















 137     private String requestURI() {
 138         URI uri = request.uri();
 139         String method = request.method();
 140 
 141         if ((request.proxy() == null && !method.equals("CONNECT"))
 142                 || request.isWebSocket()) {
 143             return getPathAndQuery(uri);
 144         }
 145         if (request.secure()) {
 146             if (request.method().equals("CONNECT")) {
 147                 // use authority for connect itself
 148                 return authorityString(request.authority());
 149             } else {
 150                 // requests over tunnel do not require full URL
 151                 return getPathAndQuery(uri);
 152             }
 153         }
 154         return uri == null? authorityString(request.authority()) : uri.toString();
 155     }
 156 
 157     void sendHeadersOnly() throws IOException {
 158         collectHeaders();
 159         chan.write(buffers, 0, 2);
 160     }
 161 
 162     void sendRequest() throws IOException {
 163         collectHeaders();

 164         if (contentLength == 0) {
 165             chan.write(buffers, 0, 2);
 166         } else if (contentLength > 0) {
 167             writeFixedContent(true);
 168         } else {
 169             writeStreamedContent(true);
 170         }
 171         setFinished();
 172     }
 173 
 174     private boolean finished;
 175 
 176     synchronized boolean finished() {
 177         return  finished;
 178     }
 179 
 180     synchronized void setFinished() {
 181         finished = true;
 182     }
 183 
 184     private void collectHeaders() throws IOException {
 185         if (Log.requests() && request != null) {
 186             Log.logRequest(request.toString());
 187         }
 188         String uriString = requestURI();
 189         StringBuilder sb = new StringBuilder(64);
 190         sb.append(request.method())
 191           .append(' ')
 192           .append(uriString)
 193           .append(" HTTP/1.1\r\n");
 194         String cmd = sb.toString();
 195 
 196         buffers[0] = ByteBuffer.wrap(cmd.getBytes(StandardCharsets.US_ASCII));
 197         URI uri = request.uri();
 198         if (uri != null) {
 199             systemHeaders.setHeader("Host", uri.getHost());
 200         }
 201         if (request == null) {
 202             // this is not a user request. No content
 203             contentLength = 0;
 204         } else {
 205             contentLength = requestProc.onRequestStart(request, flowController);
 206         }
 207 
 208         if (contentLength == 0) {
 209             systemHeaders.setHeader("Content-Length", "0");
 210             collectHeaders0();
 211         } else if (contentLength > 0) {
 212             /* [0] request line [1] headers [2] body  */
 213             systemHeaders.setHeader("Content-Length",
 214                                     Integer.toString((int) contentLength));
 215             streaming = false;
 216             collectHeaders0();
 217             buffers[2] = chan.getBuffer();
 218         } else {
 219             /* Chunked:




  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  */
  24 package java.net.http;
  25 
  26 import java.io.IOException;
  27 import java.net.URI;
  28 import java.nio.ByteBuffer;
  29 import java.util.List;
  30 import java.util.Map;
  31 import java.util.Set;
  32 import java.net.InetSocketAddress;
  33 import java.net.http.HttpConnection.Mode;
  34 import java.nio.charset.StandardCharsets;
  35 import java.util.function.LongConsumer;
  36 import static java.nio.charset.StandardCharsets.US_ASCII;
  37 
  38 /**
  39  *  A HTTP/1.1 request.
  40  *
  41  * send() -> Writes the request + body to the given channel, in one blocking
  42  * operation.
  43  */
  44 class Http1Request {
  45 
  46     final HttpRequestImpl request;
  47     final HttpConnection chan;
  48     // Multiple buffers are used to hold different parts of request
  49     // See line 206 and below for description
  50     final ByteBuffer[] buffers;
  51     final HttpRequest.BodyProcessor requestProc;
  52     final HttpHeaders userHeaders;
  53     final HttpHeadersImpl systemHeaders;
  54     final LongConsumer flowController;
  55     boolean streaming;
  56     long contentLength;
  57 
  58     Http1Request(HttpRequestImpl request, HttpConnection connection)
  59         throws IOException
  60     {
  61         this.request = request;
  62         this.chan = connection;
  63         buffers = new ByteBuffer[5]; // TODO: check
  64         this.requestProc = request.requestProcessor();
  65         this.userHeaders = request.getUserHeaders();
  66         this.systemHeaders = request.getSystemHeaders();
  67         this.flowController = this::dummy;
  68     }
  69 
  70     private void logHeaders() throws IOException {
  71         StringBuilder sb = new StringBuilder(256);
  72         sb.append("REQUEST HEADERS:\r\n");
  73         collectHeaders1(sb, request, systemHeaders);


  76     }
  77 
  78     private void dummy(long x) {
  79         // not used in this class
  80     }
  81 
  82     private void collectHeaders0() throws IOException {
  83         if (Log.headers()) {
  84             logHeaders();
  85         }
  86         StringBuilder sb = new StringBuilder(256);
  87         collectHeaders1(sb, request, systemHeaders);
  88         collectHeaders1(sb, request, userHeaders);
  89         sb.append("\r\n");
  90         String headers = sb.toString();
  91         buffers[1] = ByteBuffer.wrap(headers.getBytes(StandardCharsets.US_ASCII));
  92     }
  93 
  94     private void collectHeaders1(StringBuilder sb,
  95                                  HttpRequestImpl request,
  96                                  HttpHeaders headers)
  97         throws IOException
  98     {
  99         Map<String,List<String>> h = headers.map();
 100         Set<Map.Entry<String,List<String>>> entries = h.entrySet();
 101 
 102         for (Map.Entry<String,List<String>> entry : entries) {
 103             String key = entry.getKey();
 104             sb.append(key).append(": ");
 105             List<String> values = entry.getValue();
 106             int num = values.size();
 107             for (String value : values) {
 108                 sb.append(value);
 109                 if (--num > 0) {
 110                     sb.append(',');
 111                 }
 112             }
 113             sb.append("\r\n");
 114         }
 115     }
 116 


 117     private String getPathAndQuery(URI uri) {
 118         String path = uri.getPath();
 119         String query = uri.getQuery();
 120         if (path == null || path.equals("")) {
 121             path = "/";
 122         }
 123         if (query == null) {
 124             query = "";
 125         }
 126         if (query.equals("")) {
 127             return path;
 128         } else {
 129             return path + "?" + query;
 130         }
 131     }
 132 
 133     private String authorityString(InetSocketAddress addr) {
 134         return addr.getHostString() + ":" + addr.getPort();
 135     }
 136 
 137     private String hostString() {
 138         URI uri = request.uri();
 139         int port = uri.getPort();
 140         String host = uri.getHost();
 141 
 142         boolean defaultPort;
 143         if (port == -1)
 144             defaultPort = true;
 145         else if (request.secure())
 146             defaultPort = port == 443;
 147         else
 148             defaultPort = port == 80;
 149 
 150         if (defaultPort)
 151             return host;
 152         else
 153             return host + ":" + Integer.toString(port);
 154     }
 155 
 156     private String requestURI() {
 157         URI uri = request.uri();
 158         String method = request.method();
 159 
 160         if ((request.proxy() == null && !method.equals("CONNECT"))
 161                 || request.isWebSocket()) {
 162             return getPathAndQuery(uri);
 163         }
 164         if (request.secure()) {
 165             if (request.method().equals("CONNECT")) {
 166                 // use authority for connect itself
 167                 return authorityString(request.authority());
 168             } else {
 169                 // requests over tunnel do not require full URL
 170                 return getPathAndQuery(uri);
 171             }
 172         }
 173         return uri == null? authorityString(request.authority()) : uri.toString();
 174     }
 175 
 176     void sendHeadersOnly() throws IOException {
 177         collectHeaders();
 178         chan.write(buffers, 0, 2);
 179     }
 180 
 181     void sendRequest() throws IOException {
 182         collectHeaders();
 183         chan.configureMode(Mode.BLOCKING);
 184         if (contentLength == 0) {
 185             chan.write(buffers, 0, 2);
 186         } else if (contentLength > 0) {
 187             writeFixedContent(true);
 188         } else {
 189             writeStreamedContent(true);
 190         }
 191         setFinished();
 192     }
 193 
 194     private boolean finished;
 195 
 196     synchronized boolean finished() {
 197         return  finished;
 198     }
 199 
 200     synchronized void setFinished() {
 201         finished = true;
 202     }
 203 
 204     private void collectHeaders() throws IOException {
 205         if (Log.requests() && request != null) {
 206             Log.logRequest(request.toString());
 207         }
 208         String uriString = requestURI();
 209         StringBuilder sb = new StringBuilder(64);
 210         sb.append(request.method())
 211           .append(' ')
 212           .append(uriString)
 213           .append(" HTTP/1.1\r\n");
 214         String cmd = sb.toString();
 215 
 216         buffers[0] = ByteBuffer.wrap(cmd.getBytes(StandardCharsets.US_ASCII));
 217         URI uri = request.uri();
 218         if (uri != null) {
 219             systemHeaders.setHeader("Host", hostString());
 220         }
 221         if (request == null) {
 222             // this is not a user request. No content
 223             contentLength = 0;
 224         } else {
 225             contentLength = requestProc.onRequestStart(request, flowController);
 226         }
 227 
 228         if (contentLength == 0) {
 229             systemHeaders.setHeader("Content-Length", "0");
 230             collectHeaders0();
 231         } else if (contentLength > 0) {
 232             /* [0] request line [1] headers [2] body  */
 233             systemHeaders.setHeader("Content-Length",
 234                                     Integer.toString((int) contentLength));
 235             streaming = false;
 236             collectHeaders0();
 237             buffers[2] = chan.getBuffer();
 238         } else {
 239             /* Chunked:


< prev index next >