001: /*
002: * Copyright (c) 2001 by Matt Welsh and The Regents of the University of
003: * California. All rights reserved.
004: *
005: * Permission to use, copy, modify, and distribute this software and its
006: * documentation for any purpose, without fee, and without written agreement is
007: * hereby granted, provided that the above copyright notice and the following
008: * two paragraphs appear in all copies of this software.
009: *
010: * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
011: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
012: * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
013: * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014: *
015: * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
016: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
017: * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
018: * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
019: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
020: *
021: * Author: Matt Welsh <mdw@cs.berkeley.edu>
022: *
023: */
024:
025: package seda.sandStorm.lib.http;
026:
027: import seda.sandStorm.api.*;
028: import seda.sandStorm.lib.aSocket.*;
029: import seda.sandStorm.core.*;
030:
031: import java.util.*;
032: import java.io.*;
033: import java.net.*;
034:
035: /**
036: * This class represents a single HTTP connection. When an httpServer
037: * receives a connection, an httpConnection is pushed to the user.
038: * To send HTTP responses to a client, you can enqueue an httpResponse
039: * object on the corresponding httpConnection.
040: *
041: * @author Matt Welsh
042: * @see httpRequest
043: * @see httpResponse
044: */
045: public class httpConnection extends SimpleSink implements httpConst,
046: QueueElementIF {
047:
048: private static final boolean DEBUG = false;
049:
050: private ATcpConnection tcpconn;
051: private httpServer hs;
052: private SinkIF compQ;
053: private httpPacketReader hpr;
054:
055: /**
056: * Can be used by applications to associate an arbitrary data object
057: * with this connection.
058: */
059: public Object userTag;
060:
061: /**
062: * Package-internal: Create an httpConnection with the given TCP
063: * connection and completion queue.
064: */
065: httpConnection(ATcpConnection tcpconn, httpServer hs, SinkIF compQ) {
066: this .tcpconn = tcpconn;
067: this .hs = hs;
068: this .compQ = compQ;
069: this .hpr = new httpPacketReader(this , compQ);
070:
071: // Push myself to user
072: compQ.enqueue_lossy(this );
073: }
074:
075: /**
076: * Package-internal: Parse the data contained in the given TCP packet.
077: */
078: void parsePacket(ATcpInPacket pkt) throws IOException {
079: hpr.parsePacket(pkt);
080: }
081:
082: /**
083: * Return the ATcpConnection associated with this connection.
084: */
085: public ATcpConnection getConnection() {
086: return tcpconn;
087: }
088:
089: public String toString() {
090: return "httpConnection [conn=" + tcpconn + "]";
091: //return "httpConnection [conn=]";
092: }
093:
094: /* SinkIF methods ***********************************************/
095:
096: /**
097: * Enqueue outgoing data on this connection. The 'element' must be
098: * of type httpResponder.
099: */
100: public void enqueue(QueueElementIF element) throws SinkException {
101: if (DEBUG)
102: System.err.println("httpConnection.enqueue: " + element);
103: httpResponder resp = (httpResponder) element;
104: httpResponse packet = resp.getResponse();
105: BufferElement bufarr[] = packet.getBuffers(resp.sendHeader());
106: tcpconn.enqueue_many(bufarr);
107: }
108:
109: /**
110: * Enqueue outgoing data on this connection. The 'element' must be
111: * of type httpResponder.
112: */
113: public boolean enqueue_lossy(QueueElementIF element) {
114: if (DEBUG)
115: System.err.println("httpConnection.enqueue_lossy: "
116: + element);
117: httpResponder resp = (httpResponder) element;
118: httpResponse packet = resp.getResponse();
119: BufferElement bufarr[] = packet.getBuffers(resp.sendHeader());
120: try {
121: tcpconn.enqueue_many(bufarr);
122: } catch (SinkException se) {
123: return false;
124: }
125: return true;
126: }
127:
128: /**
129: * Enqueue outgoing data on this connection. Each item in the
130: * elements array must be of type httpResponse.
131: */
132: public void enqueue_many(QueueElementIF elements[])
133: throws SinkException {
134: for (int i = 0; i < elements.length; i++) {
135: enqueue(elements[i]);
136: }
137: }
138:
139: /**
140: * Return the number of outgoing packets waiting to be sent.
141: */
142: public int size() {
143: return tcpconn.size();
144: }
145:
146: /**
147: * Close the connection.
148: */
149: public void close(final SinkIF compQ) throws SinkClosedException {
150: // XXX For now, allow a connection to be closed multiple times.
151: // Tricky bit below: Provide anonymous SinkIF as 'compQ' which
152: // we re-enqueue onto user compQ as appropriate SinkDrainedEvent!
153:
154: hs.cleanupConnection(this );
155: tcpconn.close(new SimpleSink() {
156: public void enqueue(QueueElementIF qel)
157: throws SinkException {
158: compQ.enqueue(new SinkClosedEvent(httpConnection.this ));
159: }
160: });
161: }
162:
163: /**
164: * Flush the connection; a SinkFlushedEvent will be pushed to the
165: * user when all packets have drained.
166: */
167: public void flush(SinkIF compQ) throws SinkClosedException {
168: tcpconn.flush(compQ);
169: }
170:
171: public Object enqueue_prepare(QueueElementIF enqueueMe[])
172: throws SinkException {
173: return tcpconn.enqueue_prepare(enqueueMe);
174: }
175:
176: public void enqueue_commit(Object key) {
177: tcpconn.enqueue_commit(key);
178: }
179:
180: public void enqueue_abort(Object key) {
181: tcpconn.enqueue_abort(key);
182: }
183:
184: }
|