package com.koushikdutta.async.http; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.FilteredDataEmitter; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.http.body.AsyncHttpRequestBody; import com.koushikdutta.async.http.body.JSONObjectBody; import com.koushikdutta.async.http.body.MultipartFormDataBody; import com.koushikdutta.async.http.body.StringBody; import com.koushikdutta.async.http.body.UrlEncodedFormBody; import com.koushikdutta.async.http.filter.ChunkedInputFilter; import com.koushikdutta.async.http.filter.ContentLengthFilter; import com.koushikdutta.async.http.filter.GZIPInputFilter; import com.koushikdutta.async.http.filter.InflaterInputFilter; public class HttpUtil { public static AsyncHttpRequestBody getBody(DataEmitter emitter, CompletedCallback reporter, Headers headers) { String contentType = headers.get("Content-Type"); if (contentType != null) { String[] values = contentType.split(";"); for (int i = 0; i < values.length; i++) { values[i] = values[i].trim(); } for (String ct: values) { if (UrlEncodedFormBody.CONTENT_TYPE.equals(ct)) { return new UrlEncodedFormBody(); } if (JSONObjectBody.CONTENT_TYPE.equals(ct)) { return new JSONObjectBody(); } if (StringBody.CONTENT_TYPE.equals(ct)) { return new StringBody(); } if (MultipartFormDataBody.CONTENT_TYPE.equals(ct)) { return new MultipartFormDataBody(values); } } } return null; } static class EndEmitter extends FilteredDataEmitter { private EndEmitter() { } public static EndEmitter create(AsyncServer server, final Exception e) { final EndEmitter ret = new EndEmitter(); // don't need to worry about any race conditions with post and this return value // since we are in the server thread. server.post(new Runnable() { @Override public void run() { ret.report(e); } }); return ret; } } public static DataEmitter getBodyDecoder(DataEmitter emitter, Protocol protocol, Headers headers, boolean server) { long _contentLength; try { _contentLength = Long.parseLong(headers.get("Content-Length")); } catch (Exception ex) { _contentLength = -1; } final long contentLength = _contentLength; if (-1 != contentLength) { if (contentLength < 0) { EndEmitter ender = EndEmitter.create(emitter.getServer(), new BodyDecoderException("not using chunked encoding, and no content-length found.")); ender.setDataEmitter(emitter); emitter = ender; return emitter; } if (contentLength == 0) { EndEmitter ender = EndEmitter.create(emitter.getServer(), null); ender.setDataEmitter(emitter); emitter = ender; return emitter; } ContentLengthFilter contentLengthWatcher = new ContentLengthFilter(contentLength); contentLengthWatcher.setDataEmitter(emitter); emitter = contentLengthWatcher; } else if ("chunked".equalsIgnoreCase(headers.get("Transfer-Encoding"))) { ChunkedInputFilter chunker = new ChunkedInputFilter(); chunker.setDataEmitter(emitter); emitter = chunker; } else { if ((server || protocol == Protocol.HTTP_1_1) && !"close".equalsIgnoreCase(headers.get("Connection"))) { // if this is the server, and the client has not indicated a request body, the client is done EndEmitter ender = EndEmitter.create(emitter.getServer(), null); ender.setDataEmitter(emitter); emitter = ender; return emitter; } } if ("gzip".equals(headers.get("Content-Encoding"))) { GZIPInputFilter gunzipper = new GZIPInputFilter(); gunzipper.setDataEmitter(emitter); emitter = gunzipper; } else if ("deflate".equals(headers.get("Content-Encoding"))) { InflaterInputFilter inflater = new InflaterInputFilter(); inflater.setDataEmitter(emitter); emitter = inflater; } // conversely, if this is the client (http 1.0), and the server has not indicated a request body, we do not report // the close/end event until the server actually closes the connection. return emitter; } public static boolean isKeepAlive(Protocol protocol, Headers headers) { // connection is always keep alive as this is an http/1.1 client String connection = headers.get("Connection"); if (connection == null) return protocol == Protocol.HTTP_1_1; return "keep-alive".equalsIgnoreCase(connection); } public static boolean isKeepAlive(String protocol, Headers headers) { // connection is always keep alive as this is an http/1.1 client String connection = headers.get("Connection"); if (connection == null) return Protocol.get(protocol) == Protocol.HTTP_1_1; return "keep-alive".equalsIgnoreCase(connection); } public static int contentLength(Headers headers) { String cl = headers.get("Content-Length"); if (cl == null) return -1; try { return Integer.parseInt(cl); } catch (NumberFormatException e) { return -1; } } }