Connection.java
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one
00003  * or more contributor license agreements.  See the NOTICE file
00004  * distributed with this work for additional information
00005  * regarding copyright ownership.  The ASF licenses this file
00006  * to you under the Apache License, Version 2.0 (the
00007  * "License"); you may not use this file except in compliance
00008  * with the License.  You may obtain a copy of the License at
00009  *
00010  *   http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing,
00013  * software distributed under the License is distributed on an
00014  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
00015  * KIND, either express or implied.  See the License for the
00016  * specific language governing permissions and limitations
00017  * under the License.    
00018  */
00019 package org.apache.xmlrpc.webserver;
00020 
00021 import java.io.BufferedInputStream;
00022 import java.io.BufferedOutputStream;
00023 import java.io.ByteArrayOutputStream;
00024 import java.io.IOException;
00025 import java.io.InputStream;
00026 import java.io.OutputStream;
00027 import java.io.UnsupportedEncodingException;
00028 import java.net.Socket;
00029 import java.net.SocketException;
00030 import java.util.Iterator;
00031 import java.util.Map;
00032 import java.util.StringTokenizer;
00033 
00034 import org.apache.xmlrpc.common.ServerStreamConnection;
00035 import org.apache.xmlrpc.common.XmlRpcHttpRequestConfig;
00036 import org.apache.xmlrpc.common.XmlRpcNotAuthorizedException;
00037 import org.apache.xmlrpc.server.XmlRpcHttpServerConfig;
00038 import org.apache.xmlrpc.server.XmlRpcStreamServer;
00039 import org.apache.xmlrpc.util.HttpUtil;
00040 import org.apache.xmlrpc.util.LimitedInputStream;
00041 import org.apache.xmlrpc.util.ThreadPool;
00042 
00043 
00044 
00049 public class Connection implements ThreadPool.InterruptableTask, ServerStreamConnection {
00050     private static final String US_ASCII = "US-ASCII";
00051     private static final byte[] ctype = toHTTPBytes("Content-Type: text/xml\r\n");
00052     private static final byte[] clength = toHTTPBytes("Content-Length: ");
00053     private static final byte[] newline = toHTTPBytes("\r\n");
00054     private static final byte[] doubleNewline = toHTTPBytes("\r\n\r\n");
00055     private static final byte[] conkeep = toHTTPBytes("Connection: Keep-Alive\r\n");
00056     private static final byte[] conclose = toHTTPBytes("Connection: close\r\n");
00057     private static final byte[] ok = toHTTPBytes(" 200 OK\r\n");
00058     private static final byte[] serverName = toHTTPBytes("Server: Apache XML-RPC 1.0\r\n");
00059     private static final byte[] wwwAuthenticate = toHTTPBytes("WWW-Authenticate: Basic realm=XML-RPC\r\n");
00060 
00061     private static abstract class RequestException extends IOException {
00062         private static final long serialVersionUID = 2113732921468653309L;
00063         private final RequestData requestData;
00064 
00065         RequestException(RequestData pData, String pMessage) {
00066             super(pMessage);
00067             requestData = pData;
00068         }
00069         RequestData getRequestData() { return requestData; }
00070     }
00071 
00072     private static class BadEncodingException extends RequestException {
00073         private static final long serialVersionUID = -2674424938251521248L;
00074         BadEncodingException(RequestData pData, String pTransferEncoding) {
00075             super(pData, pTransferEncoding);
00076         }
00077     }
00078 
00079     private static class BadRequestException extends RequestException {
00080         private static final long serialVersionUID = 3257848779234554934L;
00081         BadRequestException(RequestData pData, String pTransferEncoding) {
00082             super(pData, pTransferEncoding);
00083         }
00084     }
00085 
00089     private static final byte[] toHTTPBytes(String text) {
00090         try {
00091             return text.getBytes(US_ASCII);
00092         } catch (UnsupportedEncodingException e) {
00093             throw new Error(e.getMessage() +
00094             ": HTTP requires US-ASCII encoding");
00095         }
00096     }
00097 
00098     private final WebServer webServer;
00099     private final Socket socket;
00100     private final InputStream input;
00101     private final OutputStream output;
00102     private final XmlRpcStreamServer server;
00103     private byte[] buffer;
00104     private Map headers;
00105     private RequestData requestData;
00106     private boolean shuttingDown;
00107     private boolean firstByte;
00108 
00116     public Connection(WebServer pWebServer, XmlRpcStreamServer pServer, Socket pSocket)
00117             throws IOException {
00118         webServer = pWebServer;
00119         server = pServer;
00120         socket = pSocket;
00121         input = new BufferedInputStream(socket.getInputStream()){
00126             public void close() throws IOException {
00127             }
00128         };
00129         output = new BufferedOutputStream(socket.getOutputStream());
00130     }
00131 
00137     private RequestData getRequestConfig() throws IOException {
00138         requestData = new RequestData(this);
00139         if (headers != null) {
00140             headers.clear();
00141         }
00142         firstByte = true;
00143         XmlRpcHttpServerConfig serverConfig = (XmlRpcHttpServerConfig) server.getConfig();
00144         requestData.setBasicEncoding(serverConfig.getBasicEncoding());
00145         requestData.setContentLengthOptional(serverConfig.isContentLengthOptional());
00146         requestData.setEnabledForExtensions(serverConfig.isEnabledForExtensions());
00147         requestData.setEnabledForExceptions(serverConfig.isEnabledForExceptions());
00148 
00149         // reset user authentication
00150         String line = readLine();
00151         if (line == null  &&  firstByte) {
00152             return null;
00153         }
00154         // Netscape sends an extra \n\r after bodypart, swallow it
00155         if (line != null && line.length() == 0) {
00156             line = readLine();
00157             if (line == null  ||  line.length() == 0) {
00158                 return null;
00159             }
00160         }
00161 
00162         // tokenize first line of HTTP request
00163         StringTokenizer tokens = new StringTokenizer(line);
00164         String method = tokens.nextToken();
00165         if (!"POST".equalsIgnoreCase(method)) {
00166             throw new BadRequestException(requestData, method);
00167         }
00168         requestData.setMethod(method);
00169         tokens.nextToken(); // Skip URI
00170         String httpVersion = tokens.nextToken();
00171         requestData.setHttpVersion(httpVersion);
00172         requestData.setKeepAlive(serverConfig.isKeepAliveEnabled()
00173                 && WebServer.HTTP_11.equals(httpVersion));
00174         do {
00175             line = readLine();
00176             if (line != null) {
00177                 String lineLower = line.toLowerCase();
00178                 if (lineLower.startsWith("content-length:")) {
00179                     String cLength = line.substring("content-length:".length());
00180                     requestData.setContentLength(Integer.parseInt(cLength.trim()));
00181                 } else if (lineLower.startsWith("connection:")) {
00182                     requestData.setKeepAlive(serverConfig.isKeepAliveEnabled()
00183                             &&  lineLower.indexOf("keep-alive") > -1);
00184                 } else if (lineLower.startsWith("authorization:")) {
00185                     String credentials = line.substring("authorization:".length());
00186                     HttpUtil.parseAuthorization(requestData, credentials);
00187                 } else if (lineLower.startsWith("transfer-encoding:")) {
00188                     String transferEncoding = line.substring("transfer-encoding:".length());
00189                     String nonIdentityEncoding = HttpUtil.getNonIdentityTransferEncoding(transferEncoding);
00190                     if (nonIdentityEncoding != null) {
00191                         throw new BadEncodingException(requestData, nonIdentityEncoding);
00192                     }
00193                 }
00194             }
00195         }
00196         while (line != null && line.length() != 0);
00197 
00198         return requestData;
00199     }
00200 
00201     public void run() {
00202         try {
00203             for (int i = 0;  ;  i++) {
00204                 RequestData data = getRequestConfig();
00205                 if (data == null) {
00206                     break;
00207                 }
00208                 server.execute(data, this);
00209                 output.flush();
00210                 if (!data.isKeepAlive()  ||  !data.isSuccess()) {
00211                     break;
00212                 }
00213             }
00214         } catch (RequestException e) {
00215             webServer.log(e.getClass().getName() + ": " + e.getMessage());
00216             try {
00217                 writeErrorHeader(e.requestData, e, -1);
00218                 output.flush();
00219             } catch (IOException e1) {
00220                 /* Ignore me */
00221             }
00222         } catch (Throwable t) {
00223             if (!shuttingDown) {
00224                 webServer.log(t);
00225             }
00226         } finally {
00227             try { output.close(); } catch (Throwable ignore) {}
00228             try { input.close(); } catch (Throwable ignore) {}
00229             try { socket.close(); } catch (Throwable ignore) {}
00230         }
00231     }
00232 
00233     private String readLine() throws IOException {
00234         if (buffer == null) {
00235             buffer = new byte[2048];
00236         }
00237         int next;
00238         int count = 0;
00239         for (;;) {
00240             try {
00241                 next = input.read();
00242                 firstByte = false;
00243             } catch (SocketException e) {
00244                 if (firstByte) {
00245                     return null;
00246                 } else {
00247                     throw e;
00248                 }
00249             }
00250             if (next < 0 || next == '\n') {
00251                 break;
00252             }
00253             if (next != '\r') {
00254                 buffer[count++] = (byte) next;
00255             }
00256             if (count >= buffer.length) {
00257                 throw new IOException("HTTP Header too long");
00258             }
00259         }
00260         return new String(buffer, 0, count, US_ASCII);
00261     }
00262 
00269     public void writeResponse(RequestData pData, OutputStream pBuffer)
00270             throws IOException {
00271         ByteArrayOutputStream response = (ByteArrayOutputStream) pBuffer;
00272         writeResponseHeader(pData, response.size());
00273         response.writeTo(output);
00274     }
00275 
00281     public void writeResponseHeader(RequestData pData, int pContentLength)
00282             throws IOException {
00283         output.write(toHTTPBytes(pData.getHttpVersion()));
00284         output.write(ok);
00285         output.write(serverName);
00286         output.write(pData.isKeepAlive() ? conkeep : conclose);
00287         output.write(ctype);
00288         if (headers != null) {
00289             for (Iterator iter = headers.entrySet().iterator();  iter.hasNext();  ) {
00290                 Map.Entry entry = (Map.Entry) iter.next();
00291                 String header = (String) entry.getKey();
00292                 String value = (String) entry.getValue();
00293                 output.write(toHTTPBytes(header + ": " + value + "\r\n"));
00294             }
00295         }
00296         if (pContentLength != -1) {
00297             output.write(clength);
00298             output.write(toHTTPBytes(Integer.toString(pContentLength)));
00299             output.write(doubleNewline);
00300         } else {
00301             output.write(newline);
00302         }
00303         pData.setSuccess(true);
00304     }
00305 
00312     public void writeError(RequestData pData, Throwable pError, ByteArrayOutputStream pStream)
00313             throws IOException {
00314         writeErrorHeader(pData, pError, pStream.size());
00315         pStream.writeTo(output);
00316         output.flush();
00317     }
00318 
00325     public void writeErrorHeader(RequestData pData, Throwable pError, int pContentLength)
00326             throws IOException {
00327         if (pError instanceof BadRequestException) {
00328             final byte[] content = toHTTPBytes("Method " + pData.getMethod()
00329                     + " not implemented (try POST)\r\n");
00330             output.write(toHTTPBytes(pData.getHttpVersion()));
00331             output.write(toHTTPBytes(" 400 Bad Request"));
00332             output.write(newline);
00333             output.write(serverName);
00334             writeContentLengthHeader(content.length);
00335             output.write(newline);
00336             output.write(content);
00337         } else if (pError instanceof BadEncodingException) {
00338             final byte[] content = toHTTPBytes("The Transfer-Encoding " + pError.getMessage()
00339                     + " is not implemented.\r\n");
00340             output.write(toHTTPBytes(pData.getHttpVersion()));
00341             output.write(toHTTPBytes(" 501 Not Implemented"));
00342             output.write(newline);
00343             output.write(serverName);
00344             writeContentLengthHeader(content.length);
00345             output.write(newline);
00346             output.write(content);
00347         } else if (pError instanceof XmlRpcNotAuthorizedException) {
00348             final byte[] content = toHTTPBytes("Method " + pData.getMethod()
00349                     + " requires a " + "valid user name and password.\r\n");
00350             output.write(toHTTPBytes(pData.getHttpVersion()));
00351             output.write(toHTTPBytes(" 401 Unauthorized"));
00352             output.write(newline);
00353             output.write(serverName);
00354             writeContentLengthHeader(content.length);
00355             output.write(wwwAuthenticate);
00356             output.write(newline);
00357             output.write(content);
00358         } else {
00359             output.write(toHTTPBytes(pData.getHttpVersion()));
00360             output.write(ok);
00361             output.write(serverName);
00362             output.write(conclose);
00363             output.write(ctype);
00364             writeContentLengthHeader(pContentLength);
00365             output.write(newline);
00366         }
00367     }
00368 
00369     private void writeContentLengthHeader(int pContentLength) throws IOException {
00370         if (pContentLength == -1) {
00371             return;
00372         }
00373         output.write(clength);
00374         output.write(toHTTPBytes(Integer.toString(pContentLength)));
00375         output.write(newline);
00376     }
00377 
00380     public void setResponseHeader(String pHeader, String pValue) {
00381         headers.put(pHeader, pValue);
00382     }
00383 
00384 
00385     public OutputStream newOutputStream() throws IOException {
00386         boolean useContentLength;
00387         useContentLength = !requestData.isEnabledForExtensions()
00388             ||  !((XmlRpcHttpRequestConfig) requestData).isContentLengthOptional();
00389         if (useContentLength) {
00390             return new ByteArrayOutputStream();
00391         } else {
00392             return output;
00393         }
00394     }
00395 
00396     public InputStream newInputStream() throws IOException {
00397         int contentLength = requestData.getContentLength();
00398         if (contentLength == -1) {
00399             return input;
00400         } else {
00401             return new LimitedInputStream(input, contentLength);
00402         }
00403     }
00404 
00405     public void close() throws IOException {
00406     }
00407 
00408     public void shutdown() throws Throwable {
00409         shuttingDown = true;
00410         socket.close();
00411     }
00412 }


rosjava_core
Author(s):
autogenerated on Wed Aug 26 2015 16:06:49