Http1Server.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 /* DEBUG: section 33 Client-side Routines */
10 
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "client_side.h"
14 #include "client_side_reply.h"
15 #include "client_side_request.h"
16 #include "comm/Write.h"
17 #include "http/one/RequestParser.h"
18 #include "http/Stream.h"
19 #include "HttpHeaderTools.h"
20 #include "profiler/Profiler.h"
21 #include "servers/Http1Server.h"
22 #include "SquidConfig.h"
23 #include "Store.h"
24 
26 
27 Http::One::Server::Server(const MasterXaction::Pointer &xact, bool beHttpsServer):
28  AsyncJob("Http1::Server"),
29  ConnStateData(xact),
30  isHttpsServer(beHttpsServer)
31 {
32 }
33 
34 time_t
36 {
38 }
39 
40 void
42 {
44 
45 #if USE_OPENSSL
46  // XXX: Until we create an HttpsServer class, use this hack to allow old
47  // client_side.cc code to manipulate ConnStateData object directly
48  if (isHttpsServer) {
49  postHttpsAccept();
50  return;
51  }
52 #endif
53 
54  typedef CommCbMemFunT<Server, CommTimeoutCbParams> TimeoutDialer;
55  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
56  TimeoutDialer, this, Http1::Server::requestTimeout);
57  commSetConnTimeout(clientConnection, Config.Timeout.request_start_timeout, timeoutCall);
58  readSomeData();
59 }
60 
61 void
63 {
64  if (!handleRequestBodyData())
65  return;
66 
67  // too late to read more body
68  if (!isOpen() || stoppedReceiving())
69  return;
70 
71  readSomeData();
72 }
73 
76 {
77  PROF_start(HttpServer_parseOneRequest);
78 
79  // parser is incremental. Generate new parser state if we,
80  // a) dont have one already
81  // b) have completed the previous request parsing already
82  if (!parser_ || !parser_->needsMoreData())
83  parser_ = new Http1::RequestParser(mayTunnelUnsupportedProto());
84 
85  /* Process request */
86  Http::Stream *context = parseHttpRequest(this, parser_);
87 
88  PROF_stop(HttpServer_parseOneRequest);
89  return context;
90 }
91 
94 
95 bool
97 {
99  ClientHttpRequest *http = context->http;
100  if (context->flags.parsed_ok == 0) {
101  debugs(33, 2, "Invalid Request");
102  // determine which error page templates to use for specific parsing errors
103  err_type errPage = ERR_INVALID_REQ;
104  switch (parser_->parseStatusCode) {
106  // fall through to next case
107  case Http::scUriTooLong:
108  errPage = ERR_TOO_BIG;
109  break;
111  errPage = ERR_UNSUP_REQ;
112  break;
114  errPage = ERR_UNSUP_HTTPVERSION;
115  break;
116  default:
117  if (parser_->method() == METHOD_NONE || parser_->requestUri().length() == 0)
118  // no method or url parsed, probably is wrong protocol
119  errPage = ERR_PROTOCOL_UNKNOWN;
120  // else use default ERR_INVALID_REQ set above.
121  break;
122  }
123  // setLogUri should called before repContext->setReplyToError
124  setLogUri(http, http->uri, true);
125  const char * requestErrorBytes = inBuf.c_str();
126  if (!clientTunnelOnError(this, context, request, parser_->method(), errPage)) {
127  setReplyError(context, request, parser_->method(), errPage, parser_->parseStatusCode, requestErrorBytes);
128  // HttpRequest object not build yet, there is no reason to call
129  // clientProcessRequestFinished method
130  }
131 
132  return false;
133  }
134 
135  // TODO: move URL parse into Http Parser and INVALID_URL into the above parse error handling
137  mx->tcpClient = clientConnection;
138  if ((request = HttpRequest::FromUrl(http->uri, mx, parser_->method())) == NULL) {
139  debugs(33, 5, "Invalid URL: " << http->uri);
140  // setLogUri should called before repContext->setReplyToError
141  setLogUri(http, http->uri, true);
142 
143  const char * requestErrorBytes = inBuf.c_str();
144  if (!clientTunnelOnError(this, context, request, parser_->method(), ERR_INVALID_URL)) {
145  setReplyError(context, request, parser_->method(), ERR_INVALID_URL, Http::scBadRequest, requestErrorBytes);
146  // HttpRequest object not build yet, there is no reason to call
147  // clientProcessRequestFinished method
148  }
149  return false;
150  }
151 
152  /* RFC 2616 section 10.5.6 : handle unsupported HTTP major versions cleanly. */
153  /* We currently only support 0.9, 1.0, 1.1 properly */
154  /* TODO: move HTTP-specific processing into servers/HttpServer and such */
155  if ( (parser_->messageProtocol().major == 0 && parser_->messageProtocol().minor != 9) ||
156  (parser_->messageProtocol().major > 1) ) {
157 
158  debugs(33, 5, "Unsupported HTTP version discovered. :\n" << parser_->messageProtocol());
159  // setLogUri should called before repContext->setReplyToError
160  setLogUri(http, http->uri, true);
161 
162  const char * requestErrorBytes = NULL; //HttpParserHdrBuf(parser_);
163  if (!clientTunnelOnError(this, context, request, parser_->method(), ERR_UNSUP_HTTPVERSION)) {
164  setReplyError(context, request, parser_->method(), ERR_UNSUP_HTTPVERSION, Http::scHttpVersionNotSupported, requestErrorBytes);
165  clientProcessRequestFinished(this, request);
166  }
167  return false;
168  }
169 
170  /* compile headers */
171  if (parser_->messageProtocol().major >= 1 && !request->parseHeader(*parser_.getRaw())) {
172  debugs(33, 5, "Failed to parse request headers:\n" << parser_->mimeHeader());
173  // setLogUri should called before repContext->setReplyToError
174  setLogUri(http, http->uri, true);
175  const char * requestErrorBytes = NULL; //HttpParserHdrBuf(parser_);
176  if (!clientTunnelOnError(this, context, request, parser_->method(), ERR_INVALID_REQ)) {
177  setReplyError(context, request, parser_->method(), ERR_INVALID_REQ, Http::scBadRequest, requestErrorBytes);
178  clientProcessRequestFinished(this, request);
179  }
180  return false;
181  }
182 
183  // when absolute-URI is provided Host header should be ignored. However
184  // some code still uses Host directly so normalize it using the previously
185  // sanitized URL authority value.
186  // For now preserve the case where Host is completely absent. That matters.
187  if (const auto x = request->header.delById(Http::HOST)) {
188  debugs(33, 5, "normalize " << x << " Host header using " << request->url.authority());
189  SBuf tmp(request->url.authority());
190  request->header.putStr(Http::HOST, tmp.c_str());
191  }
192 
193  // TODO: We fill request notes here until we find a way to verify whether
194  // no ACL checking is performed before ClientHttpRequest::doCallouts().
195  if (hasNotes()) {
196  assert(!request->hasNotes());
197  request->notes()->append(notes().getRaw());
198  }
199 
200  http->request = request.getRaw();
201  HTTPMSGLOCK(http->request);
202 
203  return true;
204 }
205 
206 void
207 Http::One::Server::setReplyError(Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod& method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes)
208 {
209  quitAfterError(request.getRaw());
210  if (!context->connRegistered()) {
211  debugs(33, 2, "Client stream deregister it self, nothing to do");
212  clientConnection->close();
213  return;
214  }
215  clientStreamNode *node = context->getClientReplyContext();
216  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
217  assert (repContext);
218 
219  repContext->setReplyToError(requestError, errStatusCode, method, context->http->uri, clientConnection->remote, nullptr, requestErrorBytes, nullptr);
220 
221  assert(context->http->out.offset == 0);
222  context->pullData();
223 }
224 
225 void
227 {
228  debugs(33, 5, "Body Continuation written");
229  clientProcessRequest(this, parser_, context.getRaw());
230 }
231 
232 void
234 {
235  if (!buildHttpRequest(context))
236  return;
237 
238  ClientHttpRequest *http = context->http;
240 
241  if (request->header.has(Http::HdrType::EXPECT)) {
242  const String expect = request->header.getList(Http::HdrType::EXPECT);
243  const bool supportedExpect = (expect.caseCmp("100-continue") == 0);
244  if (!supportedExpect) {
245  clientStreamNode *node = context->getClientReplyContext();
246  quitAfterError(request.getRaw());
247  // setLogUri should called before repContext->setReplyToError
248  setLogUri(http, urlCanonicalClean(request.getRaw()));
249  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
250  assert (repContext);
252  clientConnection->remote, request.getRaw(), NULL, NULL);
253  assert(context->http->out.offset == 0);
254  context->pullData();
255  clientProcessRequestFinished(this, request);
256  return;
257  }
258 
260  ACLFilledChecklist bodyContinuationCheck(Config.accessList.forceRequestBodyContinuation, request.getRaw(), NULL);
261  if (bodyContinuationCheck.fastCheck().allowed()) {
262  debugs(33, 5, "Body Continuation forced");
263  request->forcedBodyContinuation = true;
264  //sendControlMsg
265  HttpReply::Pointer rep = new HttpReply;
267 
269  const AsyncCall::Pointer cb = asyncCall(11, 3, "Http1::Server::proceedAfterBodyContinuation", CbDialer(this, &Http1::Server::proceedAfterBodyContinuation, Http::StreamPointer(context)));
270  sendControlMsg(HttpControlMsg(rep, cb));
271  return;
272  }
273  }
274  }
275  clientProcessRequest(this, parser_, context.getRaw());
276 }
277 
278 void
280 {
282  stopReceiving("virgin request body consumer aborted"); // closes ASAP
283 }
284 
285 void
287 {
288  // the caller guarantees that we are dealing with the current context only
289  Http::StreamPointer context = pipeline.front();
290  Must(context != nullptr);
291  const ClientHttpRequest *http = context->http;
292  Must(http != NULL);
293 
294  // After sending Transfer-Encoding: chunked (at least), always send
295  // the last-chunk if there was no error, ignoring responseFinishedOrFailed.
296  const bool mustSendLastChunk = http->request->flags.chunkedReply &&
297  !http->request->flags.streamError &&
299  !context->startOfOutput();
300  const bool responseFinishedOrFailed = !rep &&
301  !receivedData.data &&
302  !receivedData.length;
303  if (responseFinishedOrFailed && !mustSendLastChunk) {
304  context->writeComplete(0);
305  return;
306  }
307 
308  if (!context->startOfOutput()) {
309  context->sendBody(receivedData);
310  return;
311  }
312 
313  assert(rep);
314  http->al->reply = rep;
315  HTTPMSGLOCK(http->al->reply);
316  context->sendStartOfMessage(rep, receivedData);
317 }
318 
319 bool
321 {
322  Http::StreamPointer context = pipeline.front();
323  Must(context != nullptr);
324 
325  // Ignore this late control message if we have started sending a
326  // reply to the user already (e.g., after an error).
327  if (context->reply) {
328  debugs(11, 2, "drop 1xx made late by " << context->reply);
329  return false;
330  }
331 
332  const ClientHttpRequest *http = context->http;
333 
334  // apply selected clientReplyContext::buildReplyHeader() mods
335  // it is not clear what headers are required for control messages
337  rep->header.putStr(Http::HdrType::CONNECTION, "keep-alive");
338  httpHdrMangleList(&rep->header, http->request, http->al, ROR_REPLY);
339 
340  MemBuf *mb = rep->pack();
341 
342  debugs(11, 2, "HTTP Client " << clientConnection);
343  debugs(11, 2, "HTTP Client CONTROL MSG:\n---------\n" << mb->buf << "\n----------");
344 
345  Comm::Write(clientConnection, mb, call);
346 
347  delete mb;
348  return true;
349 }
350 
353 {
354  return new Http1::Server(xact, false);
355 }
356 
359 {
360  return new Http1::Server(xact, true);
361 }
362 
int delById(Http::HdrType id)
Definition: HttpHeader.cc:672
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
int has(Http::HdrType id) const
Definition: HttpHeader.cc:1002
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:68
bool buildHttpRequest(Http::StreamPointer &context)
Definition: Http1Server.cc:96
#define assert(EX)
Definition: assert.h:17
bool isOpen(const int fd)
Definition: comm.cc:86
int caseCmp(char const *) const
Definition: String.cc:299
ConnStateData * NewServer(MasterXactionPointer &xact)
create a new HTTP connection handler; never returns NULL
Definition: Http1Server.cc:352
Definition: Server.h:28
void setReplyToError(err_type, Http::StatusCode, const HttpRequestMethod &, char const *, Ip::Address &, HttpRequest *, const char *, Auth::UserRequest::Pointer)
builds error using clientBuildError() and calls setReplyToError() below
void set(const AnyP::ProtocolVersion &newVersion, Http::StatusCode newStatus, const char *newReason=NULL)
Definition: StatusLine.cc:30
virtual void processParsedRequest(Http::StreamPointer &context)
start processing a freshly parsed request
Definition: Http1Server.cc:233
Definition: SBuf.h:87
virtual time_t idleTimeout() const
timeout to use when waiting for the next request
Definition: Http1Server.cc:35
HttpRequestMethod method
Definition: HttpRequest.h:102
void setLogUri(ClientHttpRequest *http, char const *uri, bool cleanUrl)
acl_access * forceRequestBodyContinuation
Definition: SquidConfig.h:400
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void removeHopByHopEntries()
Definition: HttpHeader.cc:1713
MemBuf * pack() const
Definition: HttpReply.cc:101
void proceedAfterBodyContinuation(Http::StreamPointer context)
Definition: Http1Server.cc:226
bool forcedBodyContinuation
whether we have responded with HTTP 100 or FTP 150 already
Definition: HttpRequest.h:183
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:154
void clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request)
CBDATA_NAMESPACED_CLASS_INIT(Http1, Server)
int conn
the current server connection FD
Definition: Transport.cc:26
void requestTimeout(const CommTimeoutCbParams &params)
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
virtual void handleReply(HttpReply *rep, StoreIOBuffer receivedData)
Definition: Http1Server.cc:286
NotePairs::Pointer notes()
Definition: HttpRequest.cc:681
Definition: parse.c:104
StatusCode
Definition: StatusCode.h:20
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
HttpReply * reply
void clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp, Http::Stream *context)
Manages a connection from an HTTP/1 or HTTP/0.9 client.
Definition: Http1Server.h:20
ConnStateData * NewServer(MasterXactionPointer &xact)
create a new HTTPS connection handler; never returns NULL
Definition: Http1Server.cc:358
bool streamError
Definition: RequestFlags.h:94
SBuf & authority(bool requirePort=false) const
Definition: url.cc:470
Server(const MasterXaction::Pointer &xact, const bool beHttpsServer)
Definition: Http1Server.cc:27
String getList(Http::HdrType id) const
Definition: HttpHeader.cc:819
bool chunkedReply
Definition: RequestFlags.h:92
StoreEntry * storeEntry() const
bundles HTTP 1xx reply and the "successfully forwarded" callback
Http::Stream * parseHttpRequest(ConnStateData *csd, const Http1::RequestParserPointer &hp)
struct SquidConfig::@113 accessList
uint16_t flags
Definition: Store.h:173
bool hasNotes() const
Definition: HttpRequest.h:233
ClientStreamData data
Definition: clientStream.h:94
AccessLogEntry::Pointer al
access.log entry
Http::StatusLine sline
Definition: HttpReply.h:60
virtual void noteBodyConsumerAborted(BodyPipe::Pointer)
Definition: Http1Server.cc:279
time_t request_start_timeout
Definition: SquidConfig.h:115
URL url
the request URI
Definition: HttpRequest.h:103
virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer)
Definition: Http1Server.cc:62
static HttpRequest * FromUrl(const char *url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:523
bool clientTunnelOnError(ConnStateData *conn, Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod &method, err_type requestError)
#define Must(cond)
Definition: TextException.h:89
HttpHeader header
Definition: Message.h:74
char * buf
Definition: MemBuf.h:134
RequestFlags flags
Definition: HttpRequest.h:129
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:1063
#define PROF_start(probename)
Definition: Profiler.h:62
virtual Http::Stream * parseOneRequest()
Definition: Http1Server.cc:75
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:126
time_t clientIdlePconn
Definition: SquidConfig.h:109
Definition: MemBuf.h:23
struct SquidConfig::@98 Timeout
void setReplyError(Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod &method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes)
Definition: Http1Server.cc:207
#define PROF_stop(probename)
Definition: Profiler.h:63
virtual void start()
called by AsyncStart; do not call directly
Definition: Http1Server.cc:41
virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call)
handle a control message received by context from a peer and call back
Definition: Http1Server.cc:320
bool parseHeader(Http1::Parser &)
Definition: Message.cc:223
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:552
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
C * getRaw() const
Definition: RefCount.h:74
Comm::ConnectionPointer tcpClient
the client TCP connection which originated this transaction
Definition: MasterXaction.h:53
class SquidConfig Config
Definition: SquidConfig.cc:12
void append(const NotePairs *src)
Append the entries of the src NotePairs list to our list.
Definition: Notes.cc:340
#define NULL
Definition: types.h:166
void httpHdrMangleList(HttpHeader *l, HttpRequest *request, const AccessLogEntryPointer &al, req_or_rep_t req_or_rep)
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:35
virtual void start()
called by AsyncStart; do not call directly
virtual void noteBodyConsumerAborted(BodyPipe::Pointer)=0
err_type
Definition: err_type.h:12
char * urlCanonicalClean(const HttpRequest *request)
Definition: url.cc:518

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors