@Override public boolean parsedHeader(HttpField field) { HttpHeader header = field.getHeader(); String value = field.getValue(); if (value == null) value = ""; if (header != null) { switch (header) { case EXPECT: if (_version.getVersion() >= HttpVersion.HTTP_1_1.getVersion()) { HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) { case CONTINUE: _expect100Continue = true; break; case PROCESSING: _expect102Processing = true; break; default: String[] values = value.split(","); for (int i = 0; values != null && i < values.length; i++) { expect = HttpHeaderValue.CACHE.get(values[i].trim()); if (expect == null) _expect = true; else { switch (expect) { case CONTINUE: _expect100Continue = true; break; case PROCESSING: _expect102Processing = true; break; default: _expect = true; } } } } } break; case CONTENT_TYPE: MimeTypes.Type mime = MimeTypes.CACHE.get(value); String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); if (charset != null) _request.setCharacterEncodingUnchecked(charset); break; default: } } if (field.getName() != null) _request.getHttpFields().add(field); return false; }
@Override public boolean startRequest( HttpMethod method, String methodString, ByteBuffer uri, HttpVersion httpVersion) { Connector connector = getConnector(); String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http"; headers.put(HTTPSPDYHeader.SCHEME.name(version), scheme); headers.put(HTTPSPDYHeader.METHOD.name(version), methodString); headers.put( HTTPSPDYHeader.URI.name(version), BufferUtil.toUTF8String(uri)); // TODO handle bad encodings headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString()); return false; }
@Override public void onReply(Stream stream, ReplyInfo replyInfo) { HttpExchange exchange = getHttpExchange(); if (exchange == null) return; try { HttpResponse response = exchange.getResponse(); Fields fields = replyInfo.getHeaders(); short spdy = stream.getSession().getVersion(); HttpVersion version = HttpVersion.fromString(fields.get(HTTPSPDYHeader.VERSION.name(spdy)).getValue()); response.version(version); String[] status = fields.get(HTTPSPDYHeader.STATUS.name(spdy)).getValue().split(" ", 2); Integer code = Integer.parseInt(status[0]); response.status(code); String reason = status.length < 2 ? HttpStatus.getMessage(code) : status[1]; response.reason(reason); if (responseBegin(exchange)) { for (Fields.Field field : fields) { String name = field.getName(); if (HTTPSPDYHeader.from(spdy, name) != null) continue; // TODO: handle multiple values properly HttpField httpField = new HttpField(name, field.getValue()); responseHeader(exchange, httpField); } if (responseHeaders(exchange)) { if (replyInfo.isClose()) { responseSuccess(exchange); } } } } catch (Exception x) { responseFailure(x); } }
@Override public void reply(ReplyInfo replyInfo, Callback handler) { try { Fields headers = new Fields(replyInfo.getHeaders(), false); headers.remove(HTTPSPDYHeader.SCHEME.name(version)); String status = headers.remove(HTTPSPDYHeader.STATUS.name(version)).value(); Matcher matcher = statusRegexp.matcher(status); matcher.matches(); int code = Integer.parseInt(matcher.group(1)); String reason = matcher.group(2).trim(); HttpVersion httpVersion = HttpVersion.fromString(headers.remove(HTTPSPDYHeader.VERSION.name(version)).value()); // Convert the Host header from a SPDY special header to a normal header Fields.Field host = headers.remove(HTTPSPDYHeader.HOST.name(version)); if (host != null) headers.put("host", host.value()); HttpFields fields = new HttpFields(); for (Fields.Field header : headers) { String name = camelize(header.name()); fields.put(name, header.value()); } // TODO: handle better the HEAD last parameter HttpGenerator.ResponseInfo info = new HttpGenerator.ResponseInfo(httpVersion, fields, -1, code, reason, false); send(info, null, replyInfo.isClose()); if (replyInfo.isClose()) completed(); handler.succeeded(); } catch (IOException x) { handler.failed(x); } }
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { final boolean isSmile = QueryResource.APPLICATION_SMILE.equals(request.getContentType()); final ObjectMapper objectMapper = isSmile ? smileMapper : jsonMapper; String host = hostFinder.getDefaultHost(); Query inputQuery = null; boolean hasContent = request.getContentLength() > 0 || request.getContentType() != null; boolean isQuery = request.getMethod().equals(HttpMethod.POST.asString()); long startTime = System.currentTimeMillis(); // queries only exist for POST if (isQuery) { try { inputQuery = objectMapper.readValue(request.getInputStream(), Query.class); if (inputQuery != null) { host = hostFinder.getHost(inputQuery); if (inputQuery.getId() == null) { inputQuery = inputQuery.withId(UUID.randomUUID().toString()); } } } catch (IOException e) { log.warn(e, "Exception parsing query"); final String errorMessage = e.getMessage() == null ? "no error message" : e.getMessage(); requestLogger.log( new RequestLogLine( new DateTime(), request.getRemoteAddr(), null, new QueryStats( ImmutableMap.<String, Object>of("success", false, "exception", errorMessage)))); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType(QueryResource.APPLICATION_JSON); objectMapper.writeValue(response.getOutputStream(), ImmutableMap.of("error", errorMessage)); return; } catch (Exception e) { handleException(response, objectMapper, e); return; } } URI rewrittenURI = rewriteURI(host, request); if (rewrittenURI == null) { onRewriteFailed(request, response); return; } final Request proxyRequest = getHttpClient() .newRequest(rewrittenURI) .method(request.getMethod()) .version(HttpVersion.fromString(request.getProtocol())); // Copy headers for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) { String headerName = headerNames.nextElement(); if (HttpHeader.TRANSFER_ENCODING.is(headerName)) { hasContent = true; } for (Enumeration<String> headerValues = request.getHeaders(headerName); headerValues.hasMoreElements(); ) { String headerValue = headerValues.nextElement(); if (headerValue != null) { proxyRequest.header(headerName, headerValue); } } } // Add proxy headers addViaHeader(proxyRequest); addXForwardedHeaders(proxyRequest, request); final AsyncContext asyncContext = request.startAsync(); // We do not timeout the continuation, but the proxy request asyncContext.setTimeout(0); proxyRequest.timeout(getTimeout(), TimeUnit.MILLISECONDS); if (hasContent) { if (inputQuery != null) { proxyRequest.content(new BytesContentProvider(jsonMapper.writeValueAsBytes(inputQuery))); } else { proxyRequest.content(proxyRequestContent(proxyRequest, request)); } } customizeProxyRequest(proxyRequest, request); if (isQuery) { proxyRequest.send( newMetricsEmittingProxyResponseListener(request, response, inputQuery, startTime)); } else { proxyRequest.send(newProxyResponseListener(request, response)); } }