root/trunk/whisperlib/net/http/http_client_protocol.h

Revision 7, 19.4 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Catalin Popescu
31
32 #ifndef __NET_HTTP_HTTP_CLIENT_PROTOCOL_H__
33 #define __NET_HTTP_HTTP_CLIENT_PROTOCOL_H__
34
35 #include <deque>
36 #include <utility>
37 #include <string>
38 #include <vector>
39
40 #include <whisperlib/common/base/types.h>
41 #include WHISPER_HASH_MAP_HEADER
42
43 #include <whisperlib/common/io/buffer/memory_stream.h>
44 #include <whisperlib/net/http/http_request.h>
45 #include <whisperlib/net/base/selector.h>
46 #include <whisperlib/net/base/timeouter.h>
47 #include <whisperlib/net/base/connection.h>
48 #include <whisperlib/net/base/address.h>
49 #include <whisperlib/net/url/url.h>
50
51 namespace http {
52
53 //////////////////////////////////////////////////////////////////////
54 //
55 // This determines how we behave in our communication w/ the server
56 //
57 struct ClientParams {
58   ClientParams();
59   ClientParams(const string& user_agent,
60                bool dlog_level,
61                int32 max_header_size,
62                int64 max_body_size,
63                int64 max_chunk_size,
64                int64 max_num_chunks,
65                bool  accept_no_content_length,
66                int32 max_concurrent_requests,
67                int32 max_waiting_requests,
68                int32 default_request_timeout_ms,
69                int32 connect_timeout_ms,
70                int32 write_timeout_ms,
71                int32 read_timeout_ms,
72                int32 max_output_buffer_size,
73                int32 keep_alive_sec);
74
75   // HTTP version to use
76   http::HttpVersion version_;
77
78   // We send this as user agent for all requests
79   string user_agent_;
80
81   // Log in detail ?
82   bool dlog_level_;
83
84   // How long the acceptable HTTP header can be ?
85   int32 max_header_size_;
86   // For non chunked body, how long this can be ?
87   int64 max_body_size_;
88   // For chunked body, how big one chunk can be ?
89   int64 max_chunk_size_;
90   // For chunked body, how many chuncks can we accept in a request / reply ?
91   // (-1 => no limit)
92   int64 max_num_chunks_;
93   // We read replies to end of connection ..
94   bool accept_no_content_length_;
95
96   // How many concurrent requests can we send ?
97   int32 max_concurrent_requests_;
98   // How many requests can be in the waiting queue ?
99   int32 max_waiting_requests_;
100   // Timeout for a request (begin to end - unless is a streaming server answer)
101   // We use this if request->request_timeout_ms_ is 0
102   int32 default_request_timeout_ms_;
103   // Timeout for connecting to the server
104   int32 connect_timeout_ms_;
105   // Writing timeout - from us to server
106   int32 write_timeout_ms_;
107   // Reading timeout - after starting to receive an aswer how long we
108   // wait for the next bytes
109   int32 read_timeout_ms_;
110   // How much client buffering we hold when streaming to servers
111   int32 max_output_buffer_size_;
112
113   // Do we want to keep alive the connection ?
114   int32 keep_alive_sec_;
115 };
116
117 //////////////////////////////////////////////////////////////////////
118
119 // Errors that can appear in the communication w/ the server
120 // (for http protocol errors check the server response)
121 enum ClientError {
122   // No error - just signals that the request is during processing
123   CONN_INCOMPLETE         = 0,
124   // everything finished OK
125   CONN_OK                 = 1,
126   // error in connecting to the server (probably none listening)
127   CONN_CONNECT_ERROR      = 2,
128   // timeout in connecting to the server
129   CONN_CONNECT_TIMEOUT    = 3,
130   // timeout while sending the request to the server
131   CONN_WRITE_TIMEOUT      = 4,
132   // timeout while reading the response from the server
133   CONN_READ_TIMEOUT       = 5,
134   // the server closed the connection while we were talking w/ it
135   CONN_CONNECTION_CLOSED  = 6,
136   // the request timed out (application layer)
137   CONN_REQUEST_TIMEOUT    = 7,
138   // some request on the line before this one failed..
139   CONN_DEPENDENCY_FAILURE = 8,
140   // we got too many waiting requests for this server
141   CONN_TOO_MANY_REQUESTS  = 9,
142   // we got some parsing error for the http protocol
143   CONN_HTTP_PARSING_ERROR = 10,
144   // the client requested closing of connection
145   CONN_CLIENT_CLOSE       = 11,
146   // the client tried too many times
147   CONN_TOO_MANY_RETRIES   = 12,
148 };
149
150 const char* ClientErrorName(ClientError err);
151
152 class BaseClientConnection;
153 class ClientRequest;
154
155 class BaseClientProtocol {
156  public:
157   // Creates a client - we start owning the connection !!
158   BaseClientProtocol(const ClientParams* params,
159                      http::BaseClientConnection* connection,
160                      net::HostPort server);
161   virtual ~BaseClientProtocol();
162
163   // Closes all pending requests and underlying connection.
164   void Clear();
165
166   // called when the connection got connected to the server
167   virtual bool NotifyConnected();
168   // called to more data from connection_->inbuf()
169   virtual bool NotifyConnectionRead();
170   // called when the connection handled a write
171   virtual void NotifyConnectionWrite();
172
173   // called when the connection is deleted
174   virtual void NotifyConnectionDeletion();
175
176   // called when a timeout happended - return true if not handled
177   // and connection should continue.
178   virtual bool HandleTimeout(int64 timeout_id);
179
180   // Flow control functions:
181   void PauseReading();
182   void UnpauseReading();
183   void PauseWriting();
184   void UnpauseWriting();
185
186   // How much data can be written in the output buffer of
187   // a request (request()->client_data()) to satisfy the
188   // flow control of the application.
189   int32 available_output_size() const {
190     return available_output_size_;
191   }
192   // Returns if the connection is (still) alive
193   bool IsAlive() const {
194     return connection_ != NULL;
195   }
196   BaseClientConnection* connection() {
197     return connection_;
198   }
199  protected:
200   // Helper for writing a request out to the server
201   void SendRequestToServer(ClientRequest* req);
202
203  private:
204   void HandleTimeoutEvent(int64 timeout_id);
205  protected:
206   // Timeout ids - should be used by all
207   static const int64 kConnectTimeout = 1;
208   static const int64 kWriteTimeout   = 2;
209   static const int64 kReadTimeout    = 3;
210   static const int64 kRequestTimeout = 4;
211
212   const string name_;
213   const ClientParams* params_;
214   const net::HostPort server_;
215
216   int32 available_output_size_;
217   ClientError conn_error_;
218
219   BaseClientConnection* connection_;
220   ClientRequest* current_request_;
221
222   net::Timeouter timeouter_;          // We set timeouts using this guy
223
224   int parser_read_state_;             // The last parser status returned
225   RequestParser parser_;              // parses replies for us
226  private:
227   DISALLOW_EVIL_CONSTRUCTORS(BaseClientProtocol);
228 };
229
230 //////////////////////////////////////////////////////////////////////
231 //
232 // Derive your server connection from here. You need to override the
233 // virtual functions declared in here.. Make sure that your protocol
234 // sees the payload data you receive !! (called on NotifyConnectionRead());
235 // The ClientProtocol must exist for all the duration of a connection.
236 // The connection must inform (on deletion) that is going away..
237 //
238 class BaseClientConnection {
239  public:
240   explicit BaseClientConnection(net::Selector* selector,
241                                 net::NetFactory* net_factory,
242                                 net::PROTOCOL net_protocol);
243   virtual ~BaseClientConnection();
244
245   // Called when protocol puts some data on the wire
246   virtual void NotifyWrite();
247
248   net::Selector* selector() {
249     return selector_;
250   }
251   const http::BaseClientProtocol* protocol() const {
252     return protocol_;
253   }
254   void  set_protocol(http::BaseClientProtocol* protocol) {
255     protocol_ = protocol;
256   }
257
258   void Connect(const net::HostPort& addr) {
259     if ( !net_connection_->Connect(addr) ) {
260       LOG_ERROR << "BaseClientConnection failed to connect to: " << addr;
261       ConnectionCloseHandler(net_connection_->last_error_code(),
262           net::NetConnection::CLOSE_READ_WRITE);
263     }
264     // if Connect fails, it calls ConnectionCloseHandler(errno, ..)
265   }
266   net::NetConnection::State state() const {
267     return net_connection_->state();
268   }
269   const net::HostPort& remote_address() const {
270     return net_connection_->remote_address();
271   }
272   const net::HostPort& local_address() const {
273     return net_connection_->local_address();
274   }
275   io::MemoryStream* inbuf() {
276     return net_connection_->inbuf();
277   }
278   io::MemoryStream* outbuf() {
279     return net_connection_->outbuf();
280   }
281   int64 count_bytes_written() const {
282     return net_connection_->count_bytes_written();
283   }
284   int64 count_bytes_read() const {
285     return net_connection_->count_bytes_read();
286   }
287   void FlushAndClose() {
288     net_connection_->FlushAndClose();
289   }
290   void ForceClose() {
291     net_connection_->ForceClose();
292   }
293   void RequestReadEvents(bool enable) {
294     net_connection_->RequestReadEvents(enable);
295   }
296   void RequestWriteEvents(bool enable) {
297     net_connection_->RequestWriteEvents(enable);
298   }
299  private:
300   void ConnectionConnectHandler();
301   bool ConnectionReadHandler();
302   bool ConnectionWriteHandler();
303   void ConnectionCloseHandler(int err, net::NetConnection::CloseWhat what);
304
305  private:
306    net::Selector * selector_;
307
308    // underlying TcpConnection or SslConnection
309    net::NetConnection* net_connection_;
310
311   // This guy needs to be informed about all data received and contains
312   // the communication state (when needed)
313   http::BaseClientProtocol* protocol_;
314  private:
315   DISALLOW_EVIL_CONSTRUCTORS(BaseClientConnection);
316 };
317
318 //////////////////////////////////////////////////////////////////////
319 //
320 // SimpleClientConnection - a simple implementation of
321 //     BaseClientConnection for communication over a simple, unprotected
322 //     TCP connection.
323 //
324 class SimpleClientConnection : public BaseClientConnection {
325  public:
326   explicit SimpleClientConnection(net::Selector* selector,
327                                   net::NetFactory* net_factory,
328                                   net::PROTOCOL net_protocol);
329   virtual ~SimpleClientConnection();
330  private:
331   DISALLOW_EVIL_CONSTRUCTORS(SimpleClientConnection);
332 };
333
334 //////////////////////////////////////////////////////////////////////
335 //
336 // ClientStreamingProtocol - A client that streams data to server
337 //
338 class ClientStreamingProtocol : public BaseClientProtocol {
339  public:
340   // A function for streaming more data - the ClientStreamingProtocol
341   // call this one w/ an int32 - size that it can accept to be written.
342   // If int32 is negative - is a signal that the request ended. (also the
343   // given request has some kind of finalization error set
344   typedef ResultCallback1<bool, int32> StreamingCallback;
345
346   // Creates a client - we start owning the connection !!
347   // We begin the tcp/ssl connection NOW.
348   ClientStreamingProtocol(const ClientParams* params,
349                           http::BaseClientConnection* connection,
350                           net::HostPort server);
351   virtual ~ClientStreamingProtocol();
352
353   // INTERFACE FUNCTION:
354
355   // Starts streaming - the request should contain the client request
356   // and maybe the first chunk of data. Upon more data available in the
357   // output buffer, the client protocol calls the provided function
358   // for the user to dump more data into request->request()->client_
359   // streaming_callback should be permanent.
360   // *IMPORTANT*  We never own the request or the callback
361   void BeginStreaming(ClientRequest* request,
362                       StreamingCallback* streaming_callback);
363
364
365   // INTERNAL FUNCTIONS:
366
367   // called to more data from connection_->inbuf()
368   virtual bool NotifyConnectionRead();
369   // called when the connection handled a write
370   virtual void NotifyConnectionWrite();
371   // called when the connection is deleted
372   virtual void NotifyConnectionDeletion();
373
374  private:
375   bool source_stopped_;
376   StreamingCallback* streaming_callback_;
377
378   DISALLOW_EVIL_CONSTRUCTORS(ClientStreamingProtocol);
379 };
380
381 //////////////////////////////////////////////////////////////////////
382 //
383 // ClientStreamReceiverProtocol - A client that sends a request to the
384 //       server, then receives the reply as a stream for the server.
385 //
386 class ClientStreamReceiverProtocol : public BaseClientProtocol {
387  public:
388   // Creates a client - we start owning the connection.
389   // We begin the tcp/ssl connection NOW.
390   ClientStreamReceiverProtocol(const ClientParams* params,
391                                http::BaseClientConnection* connection,
392                                net::HostPort server);
393   virtual ~ClientStreamReceiverProtocol();
394
395   // INTERFACE FUNCTION:
396
397   // Starts the given request. Upon receiving some data or on some error
398   // we call the provided callback (which should be permanent)
399   // *IMPORTANT*  We never own the request or the callback
400   void BeginStreamReceiving(ClientRequest* request,
401                             Closure* new_data_callback);
402
403   // INTERNAL FUNCTIONS:
404
405   // called by the connection to read more data from connection_->inbuf()
406   virtual bool NotifyConnectionRead();
407   // called when the connection is deleted
408   virtual void NotifyConnectionDeletion();
409
410  private:
411   ClientRequest* request_;
412   Closure* streaming_callback_;
413
414   DISALLOW_EVIL_CONSTRUCTORS(ClientStreamReceiverProtocol);
415 };
416
417 ///////////////////////////////////////////////////////////////////////
418 //
419 // A "normal" client - for sending and receiving full described
420 // requests in one buffer shot.
421 //
422 class ClientProtocol : public BaseClientProtocol  {
423  public:
424   ClientProtocol(const ClientParams* params,
425                  http::BaseClientConnection* connection,
426                  net::HostPort server);
427   // NOTE: Be sure you call Clear() to complete all pending queries,
428   //       before deleting the ClientProtocol !
429   virtual ~ClientProtocol();
430
431   // INTERFACE FUNCTION:
432
433   // The normal request / reply communication paradigm - we start this
434   // request and call once the done callback when the request is done.
435   void SendRequest(ClientRequest* request, Closure* done_callback);
436
437   int32 num_active_requests() const { return active_requests_.size(); }
438   int32 num_waiting_requests() const { return waiting_requests_.size(); }
439
440   // INTERNAL FUNCTIONS:
441
442
443   // called when the connection got connected to the server
444   virtual bool NotifyConnected();
445   // called to more data from connection_->inbuf()
446   virtual bool NotifyConnectionRead();
447   // called when the connection is deleted
448   virtual void NotifyConnectionDeletion();
449
450   // We want to expire the proper connection
451   bool HandleTimeout(int64 timeout_id);
452
453   // Calls are resolve callbacks and closes the connection
454   void ResolveAllRequestsWithError();
455
456  private:
457   // Finds which active request is currently in reading process (based
458   // on the request_id header
459   bool IdentifyReadingRequest();
460
461   // Writes some requests to the server, until the active queue is full
462   void WriteRequestsToServer();
463
464
465   // each new request gets a unique ID assigned as crt_id_ (after which
466   // crt_id_ is incremented)
467   int64 crt_id_;
468
469   // The active requests are those sent to the server. This is at most
470   // of size params_->max_concurrent_requests_ (in normal HTTP
471   // conversation this would be 1, but we know to interleave the requests.
472   typedef hash_map<int64, ClientRequest*> RequestMap;
473   RequestMap active_requests_;
474
475   // Requests waiting for processing (to become active)
476   typedef deque<ClientRequest*> RequestsQueue;
477   RequestsQueue waiting_requests_;
478
479   // What closures to call upon completion
480   typedef hash_map<ClientRequest*, Closure*> CallbackMap;
481   CallbackMap callback_map_;
482
483   // Request currently in reading ..
484   ClientRequest* reading_request_;
485
486   DISALLOW_EVIL_CONSTRUCTORS(ClientProtocol);
487 };
488
489 //////////////////////////////////////////////////////////////////////
490
491 class ClientRequest  {
492  public:
493   // One empty request
494   ClientRequest();
495
496   // Constructs a request w/ a *good* URL
497   ClientRequest(HttpMethod http_method, const URL* url);
498
499   // Constructs a request w/ a *good* escaped URI path/query
500   // (e.g. "/a%20b?x=%25-%3D" not "/a b?x=%-="
501   ClientRequest(HttpMethod http_method,
502                 const string& escaped_query_path);
503   // Constructs a request w/ an unescaped URI path / query.
504   // (e.g. unescaped_path = "/a b", unescaped_query_comp = [("x", "%-=")]
505   //  will result in a request URI of "/a%20b?x=%25-%3D"
506   // If query component is null - no query component is given
507   ClientRequest(HttpMethod http_method,
508                 const string& unescaped_path,
509                 const vector< pair<string, string> >* unescaped_query_comp);
510   // Same as abive, but you can also specify a fragment (the piece after #)
511   ClientRequest(HttpMethod http_method,
512                 const string& unescaped_path,
513                 const vector< pair<string, string> >* unescaped_query_comp,
514                 const string& fragment);
515
516   // Given a set of unescaped query components returns the escaped well formed
517   // query.
518   // (e.g. unescaped_query_comp = [("x", "%-=")] => "x=%25-%3D"
519   // Use this to set the body of a POST with form parameters !
520   static string EscapeQueryParameters(
521       const vector< pair<string, string> >& unescaped_query_comp);
522
523   http::Request* request() { return &request_; }
524   http::ClientError error() const { return error_; }
525   bool is_finalized() const {
526     return error_ >= CONN_OK;
527   }
528
529   int32 request_timeout_ms() const { return request_timeout_ms_; }
530   int64 request_id() const { return request_id_; }
531   bool is_pure_dumping() const { return is_pure_dumping_; }
532
533   void set_error(http::ClientError error) { error_ = error; }
534   void set_request_timeout_ms(int32 t) { request_timeout_ms_ = t; }
535   void set_request_id(int64 request_id) { request_id_ = request_id; }
536   void set_is_pure_dumping(bool val) { is_pure_dumping_ = val; }
537
538   string name() const {
539     return strutil::StrTrim(
540         request_.client_header()->ComposeFirstLine()) +
541         strutil::StringPrintf(" req_id: %lld",
542                               static_cast<long long int>(request_id_));
543   }
544   const char* ClientErrorName() const {
545     return http::ClientErrorName(error_);
546   }
547  private:
548   http::Request request_;
549   http::ClientError error_;
550   // timeout for the completion of the request (begin to end).
551   // If 0 we use the default timeout from protocol params.
552   int32 request_timeout_ms_;
553   // An id for a request in a conversation with multiple concurrent
554   // request
555   int64 request_id_;
556   // If this is on we just dump the request - w/ no content length and
557   // other checks..
558   bool is_pure_dumping_;
559
560   friend class ClientProtocol;
561
562   DISALLOW_EVIL_CONSTRUCTORS(ClientRequest);
563 };
564 }
565
566
567 #endif  // __NET_HTTP_HTTP_CLIENT_PROTOCOL_H__
Note: See TracBrowser for help on using the browser.