2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 33 Client-side Routines */
12 #include "client_side.h"
13 #include "client_side_request.h"
14 #include "comm/Write.h"
15 #include "HttpHeaderTools.h"
16 #include "profiler/Profiler.h"
17 #include "servers/forward.h"
18 #include "SquidConfig.h"
23 /// Manages a connection from an HTTP client.
24 class Server
: public ConnStateData
27 Server(const MasterXaction::Pointer
&xact
, const bool beHttpsServer
);
30 void readSomeHttpData();
33 /* ConnStateData API */
34 virtual ClientSocketContext
*parseOneRequest(Http::ProtocolVersion
&ver
);
35 virtual void processParsedRequest(ClientSocketContext
*context
, const Http::ProtocolVersion
&ver
);
36 virtual void handleReply(HttpReply
*rep
, StoreIOBuffer receivedData
);
37 virtual void writeControlMsgAndCall(ClientSocketContext
*context
, HttpReply
*rep
, AsyncCall::Pointer
&call
);
38 virtual time_t idleTimeout() const;
41 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer
);
42 virtual void noteBodyConsumerAborted(BodyPipe::Pointer
);
48 void processHttpRequest(ClientSocketContext
*const context
);
49 void handleHttpRequestData();
52 HttpRequestMethod method_
; ///< parsed HTTP method
54 /// temporary hack to avoid creating a true HttpsServer class
55 const bool isHttpsServer
;
57 CBDATA_CLASS2(Server
);
62 CBDATA_NAMESPACED_CLASS_INIT(Http
, Server
);
64 Http::Server::Server(const MasterXaction::Pointer
&xact
, bool beHttpsServer
):
65 AsyncJob("Http::Server"),
67 isHttpsServer(beHttpsServer
)
72 Http::Server::idleTimeout() const
74 return Config
.Timeout
.clientIdlePconn
;
80 ConnStateData::start();
83 // XXX: Until we create an HttpsServer class, use this hack to allow old
84 // client_side.cc code to manipulate ConnStateData object directly
91 typedef CommCbMemFunT
<Server
, CommTimeoutCbParams
> TimeoutDialer
;
92 AsyncCall::Pointer timeoutCall
= JobCallback(33, 5,
93 TimeoutDialer
, this, Http::Server::requestTimeout
);
94 commSetConnTimeout(clientConnection
, Config
.Timeout
.request
, timeoutCall
);
99 Http::Server::noteMoreBodySpaceAvailable(BodyPipe::Pointer
)
101 if (!handleRequestBodyData())
104 // too late to read more body
105 if (!isOpen() || stoppedReceiving())
111 ClientSocketContext
*
112 Http::Server::parseOneRequest(Http::ProtocolVersion
&ver
)
114 ClientSocketContext
*context
= NULL
;
115 PROF_start(HttpServer_parseOneRequest
);
116 HttpParserInit(&parser_
, in
.buf
.c_str(), in
.buf
.length());
117 context
= parseHttpRequest(this, &parser_
, &method_
, &ver
);
118 PROF_stop(HttpServer_parseOneRequest
);
123 Http::Server::processParsedRequest(ClientSocketContext
*context
, const Http::ProtocolVersion
&ver
)
125 clientProcessRequest(this, &parser_
, context
, method_
, ver
);
129 Http::Server::noteBodyConsumerAborted(BodyPipe::Pointer ptr
)
131 ConnStateData::noteBodyConsumerAborted(ptr
);
132 stopReceiving("virgin request body consumer aborted"); // closes ASAP
136 Http::Server::handleReply(HttpReply
*rep
, StoreIOBuffer receivedData
)
138 // the caller guarantees that we are dealing with the current context only
139 ClientSocketContext::Pointer context
= getCurrentContext();
140 Must(context
!= NULL
);
141 const ClientHttpRequest
*http
= context
->http
;
144 // After sending Transfer-Encoding: chunked (at least), always send
145 // the last-chunk if there was no error, ignoring responseFinishedOrFailed.
146 const bool mustSendLastChunk
= http
->request
->flags
.chunkedReply
&&
147 !http
->request
->flags
.streamError
&&
148 !context
->startOfOutput();
149 const bool responseFinishedOrFailed
= !rep
&&
150 !receivedData
.data
&&
151 !receivedData
.length
;
152 if (responseFinishedOrFailed
&& !mustSendLastChunk
) {
153 context
->writeComplete(context
->clientConnection
, NULL
, 0, Comm::OK
);
157 if (!context
->startOfOutput()) {
158 context
->sendBody(rep
, receivedData
);
163 http
->al
->reply
= rep
;
164 HTTPMSGLOCK(http
->al
->reply
);
165 context
->sendStartOfMessage(rep
, receivedData
);
169 Http::Server::writeControlMsgAndCall(ClientSocketContext
*context
, HttpReply
*rep
, AsyncCall::Pointer
&call
)
171 // apply selected clientReplyContext::buildReplyHeader() mods
172 // it is not clear what headers are required for control messages
173 rep
->header
.removeHopByHopEntries();
174 rep
->header
.putStr(HDR_CONNECTION
, "keep-alive");
175 httpHdrMangleList(&rep
->header
, getCurrentContext()->http
->request
, ROR_REPLY
);
177 MemBuf
*mb
= rep
->pack();
179 debugs(11, 2, "HTTP Client " << clientConnection
);
180 debugs(11, 2, "HTTP Client CONTROL MSG:\n---------\n" << mb
->buf
<< "\n----------");
182 Comm::Write(context
->clientConnection
, mb
, call
);
188 Http::NewServer(MasterXactionPointer
&xact
)
190 return new Server(xact
, false);
194 Https::NewServer(MasterXactionPointer
&xact
)
196 return new Http::Server(xact
, true);