Path: blob/master/test/jdk/sun/net/www/httptest/HttpTransaction.java
41154 views
/*1* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.*;24import java.nio.*;25import java.nio.channels.*;26import java.net.*;27import sun.net.www.MessageHeader;2829/**30* This class encapsulates a HTTP request received and a response to be31* generated in one transaction. It provides methods for examaining the32* request from the client, and for building and sending a reply.33*/3435public class HttpTransaction {3637String command;38URI requesturi;39TestHttpServer.Server server;40MessageHeader reqheaders, reqtrailers;41String reqbody;42byte[] rspbody;43MessageHeader rspheaders, rsptrailers;44SelectionKey key;45int rspbodylen;46boolean rspchunked;4748HttpTransaction (TestHttpServer.Server server, String command,49URI requesturi, MessageHeader headers,50String body, MessageHeader trailers, SelectionKey key) {51this.command = command;52this.requesturi = requesturi;53this.reqheaders = headers;54this.reqbody = body;55this.reqtrailers = trailers;56this.key = key;57this.server = server;58}5960/**61* Get the value of a request header whose name is specified by the62* String argument.63*64* @param key the name of the request header65* @return the value of the header or null if it does not exist66*/67public String getRequestHeader (String key) {68return reqheaders.findValue (key);69}7071/**72* Get the value of a response header whose name is specified by the73* String argument.74*75* @param key the name of the response header76* @return the value of the header or null if it does not exist77*/78public String getResponseHeader (String key) {79return rspheaders.findValue (key);80}8182/**83* Get the request URI84*85* @return the request URI86*/87public URI getRequestURI () {88return requesturi;89}9091public String toString () {92StringBuffer buf = new StringBuffer();93buf.append ("Request from: ").append (key.channel().toString()).append("\r\n");94buf.append ("Command: ").append (command).append("\r\n");95buf.append ("Request URI: ").append (requesturi).append("\r\n");96buf.append ("Headers: ").append("\r\n");97buf.append (reqheaders.toString()).append("\r\n");98buf.append ("Body: ").append (reqbody).append("\r\n");99buf.append ("---------Response-------\r\n");100buf.append ("Headers: ").append("\r\n");101if (rspheaders != null) {102buf.append (rspheaders.toString()).append("\r\n");103}104String rbody = rspbody == null? "": new String (rspbody);105buf.append ("Body: ").append (rbody).append("\r\n");106return new String (buf);107}108109/**110* Get the value of a request trailer whose name is specified by111* the String argument.112*113* @param key the name of the request trailer114* @return the value of the trailer or null if it does not exist115*/116public String getRequestTrailer (String key) {117return reqtrailers.findValue (key);118}119120/**121* Add a response header to the response. Multiple calls with the same122* key value result in multiple header lines with the same key identifier123* @param key the name of the request header to add124* @param val the value of the header125*/126public void addResponseHeader (String key, String val) {127if (rspheaders == null)128rspheaders = new MessageHeader ();129rspheaders.add (key, val);130}131132/**133* Set a response header. Searches for first header with named key134* and replaces its value with val135* @param key the name of the request header to add136* @param val the value of the header137*/138public void setResponseHeader (String key, String val) {139if (rspheaders == null)140rspheaders = new MessageHeader ();141rspheaders.set (key, val);142}143144/**145* Add a response trailer to the response. Multiple calls with the same146* key value result in multiple trailer lines with the same key identifier147* @param key the name of the request trailer to add148* @param val the value of the trailer149*/150public void addResponseTrailer (String key, String val) {151if (rsptrailers == null)152rsptrailers = new MessageHeader ();153rsptrailers.add (key, val);154}155156/**157* Get the request method158*159* @return the request method160*/161public String getRequestMethod (){162return command;163}164165/**166* Perform an orderly close of the TCP connection associated with this167* request. This method guarantees that any response already sent will168* not be reset (by this end). The implementation does a shutdownOutput()169* of the TCP connection and for a period of time consumes and discards170* data received on the reading side of the connection. This happens171* in the background. After the period has expired the172* connection is completely closed.173*/174175public void orderlyClose () {176try {177server.orderlyCloseChannel (key);178} catch (IOException e) {179System.out.println (e);180}181}182183/**184* Do an immediate abortive close of the TCP connection associated185* with this request.186*/187public void abortiveClose () {188try {189server.abortiveCloseChannel(key);190} catch (IOException e) {191System.out.println (e);192}193}194195/**196* Get the SocketChannel associated with this request197*198* @return the socket channel199*/200public SocketChannel channel() {201return (SocketChannel) key.channel();202}203204/**205* Get the request entity body associated with this request206* as a single String.207*208* @return the entity body in one String209*/210public String getRequestEntityBody (){211return reqbody;212}213214/**215* Set the entity response body with the given string216* The content length is set to the length of the string217* @param body the string to send in the response218*/219public void setResponseEntityBody (String body){220rspbody = body.getBytes();221rspbodylen = body.length();222rspchunked = false;223addResponseHeader ("Content-length", Integer.toString (rspbodylen));224}225/**226* Set the entity response body with the given byte[]227* The content length is set to the gven length228* @param body the string to send in the response229*/230public void setResponseEntityBody (byte[] body, int len){231rspbody = body;232rspbodylen = len;233rspchunked = false;234addResponseHeader ("Content-length", Integer.toString (rspbodylen));235}236237238/**239* Set the entity response body by reading the given inputstream240*241* @param is the inputstream from which to read the body242*/243public void setResponseEntityBody (InputStream is) throws IOException {244byte[] buf = new byte [2048];245byte[] total = new byte [2048];246int total_len = 2048;247int c, len=0;248while ((c=is.read (buf)) != -1) {249if (len+c > total_len) {250byte[] total1 = new byte [total_len * 2];251System.arraycopy (total, 0, total1, 0, len);252total = total1;253total_len = total_len * 2;254}255System.arraycopy (buf, 0, total, len, c);256len += c;257}258setResponseEntityBody (total, len);259}260261/* chunked */262263/**264* Set the entity response body with the given array of strings265* The content encoding is set to "chunked" and each array element266* is sent as one chunk.267* @param body the array of string chunks to send in the response268*/269public void setResponseEntityBody (String[] body) {270StringBuffer buf = new StringBuffer ();271int len = 0;272for (int i=0; i<body.length; i++) {273String chunklen = Integer.toHexString (body[i].length());274len += body[i].length();275buf.append (chunklen).append ("\r\n");276buf.append (body[i]).append ("\r\n");277}278buf.append ("0\r\n");279rspbody = new String (buf).getBytes();280rspbodylen = rspbody.length;281rspchunked = true;282addResponseHeader ("Transfer-encoding", "chunked");283}284285/**286* Send the response with the current set of response parameters287* but using the response code and string tag line as specified288* @param rCode the response code to send289* @param rTag the response string to send with the response code290*/291public void sendResponse (int rCode, String rTag) throws IOException {292OutputStream os = new TestHttpServer.NioOutputStream(channel());293PrintStream ps = new PrintStream (os);294ps.print ("HTTP/1.1 " + rCode + " " + rTag + "\r\n");295if (rspheaders != null) {296rspheaders.print (ps);297} else {298ps.print ("\r\n");299}300ps.flush ();301if (rspbody != null) {302os.write (rspbody, 0, rspbodylen);303os.flush();304}305if (rsptrailers != null) {306rsptrailers.print (ps);307} else if (rspchunked) {308ps.print ("\r\n");309}310ps.flush();311}312313/* sends one byte less than intended */314315public void sendPartialResponse (int rCode, String rTag)throws IOException {316OutputStream os = new TestHttpServer.NioOutputStream(channel());317PrintStream ps = new PrintStream (os);318ps.print ("HTTP/1.1 " + rCode + " " + rTag + "\r\n");319ps.flush();320if (rspbody != null) {321os.write (rspbody, 0, rspbodylen-1);322os.flush();323}324if (rsptrailers != null) {325rsptrailers.print (ps);326}327ps.flush();328}329}330331332