| 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__ |
|---|