// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.fcgi.client.http; import java.net.URI; import java.util.Locale; import org.eclipse.jetty.client.HttpChannel; import org.eclipse.jetty.client.HttpContent; import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.HttpSender; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.generator.ClientGenerator; import org.eclipse.jetty.fcgi.generator.Generator; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Jetty; public class HttpSenderOverFCGI extends HttpSender { private final ClientGenerator generator; public HttpSenderOverFCGI(HttpChannel channel) { super(channel); this.generator = new ClientGenerator(channel.getHttpDestination().getHttpClient().getByteBufferPool()); } @Override protected HttpChannelOverFCGI getHttpChannel() { return (HttpChannelOverFCGI)super.getHttpChannel(); } @Override protected void sendHeaders(HttpExchange exchange, HttpContent content, Callback callback) { Request request = exchange.getRequest(); // Copy the request headers to be able to convert them properly HttpFields headers = new HttpFields(); for (HttpField field : request.getHeaders()) headers.put(field); HttpFields fcgiHeaders = new HttpFields(); // FastCGI headers based on the URI URI uri = request.getURI(); String path = uri == null ? request.getPath() : uri.getRawPath(); fcgiHeaders.put(FCGI.Headers.DOCUMENT_URI, path); String query = uri == null ? null : uri.getRawQuery(); fcgiHeaders.put(FCGI.Headers.QUERY_STRING, query == null ? "" : query); // FastCGI headers based on HTTP headers HttpField httpField = headers.remove(HttpHeader.AUTHORIZATION); if (httpField != null) fcgiHeaders.put(FCGI.Headers.AUTH_TYPE, httpField.getValue()); httpField = headers.remove(HttpHeader.CONTENT_LENGTH); fcgiHeaders.put(FCGI.Headers.CONTENT_LENGTH, httpField == null ? "" : httpField.getValue()); httpField = headers.remove(HttpHeader.CONTENT_TYPE); fcgiHeaders.put(FCGI.Headers.CONTENT_TYPE, httpField == null ? "" : httpField.getValue()); // FastCGI headers that are not based on HTTP headers nor URI fcgiHeaders.put(FCGI.Headers.REQUEST_METHOD, request.getMethod()); fcgiHeaders.put(FCGI.Headers.SERVER_PROTOCOL, request.getVersion().asString()); fcgiHeaders.put(FCGI.Headers.GATEWAY_INTERFACE, "CGI/1.1"); fcgiHeaders.put(FCGI.Headers.SERVER_SOFTWARE, "Jetty/" + Jetty.VERSION); // Translate remaining HTTP header into the HTTP_* format for (HttpField field : headers) { String name = field.getName(); String fcgiName = "HTTP_" + name.replaceAll("-", "_").toUpperCase(Locale.ENGLISH); fcgiHeaders.add(fcgiName, field.getValue()); } // Give a chance to the transport implementation to customize the FastCGI headers HttpClientTransportOverFCGI transport = (HttpClientTransportOverFCGI)getHttpChannel().getHttpDestination().getHttpClient().getTransport(); transport.customize(request, fcgiHeaders); int id = getHttpChannel().getRequest(); boolean hasContent = content.hasContent(); Generator.Result headersResult = generator.generateRequestHeaders(id, fcgiHeaders, hasContent ? callback : Callback.NOOP); if (hasContent) { getHttpChannel().flush(headersResult); } else { Generator.Result noContentResult = generator.generateRequestContent(id, BufferUtil.EMPTY_BUFFER, true, callback); getHttpChannel().flush(headersResult, noContentResult); } } @Override protected void sendContent(HttpExchange exchange, HttpContent content, Callback callback) { if (content.isConsumed()) { callback.succeeded(); } else { int request = getHttpChannel().getRequest(); Generator.Result result = generator.generateRequestContent(request, content.getByteBuffer(), content.isLast(), callback); getHttpChannel().flush(result); } } @Override protected void sendTrailers(HttpExchange exchange, Callback callback) { callback.succeeded(); } }