1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Copyright 2005 Google Inc.  All Rights Reserved.
29//
30
31
32#ifndef TALK_BASE_HTTPBASE_H__
33#define TALK_BASE_HTTPBASE_H__
34
35#include "talk/base/httpcommon.h"
36
37namespace talk_base {
38
39class StreamInterface;
40
41///////////////////////////////////////////////////////////////////////////////
42// HttpParser - Parses an HTTP stream provided via Process and end_of_input, and
43// generates events for:
44//  Structural Elements: Leader, Headers, Document Data
45//  Events: End of Headers, End of Document, Errors
46///////////////////////////////////////////////////////////////////////////////
47
48class HttpParser {
49public:
50  enum ProcessResult { PR_CONTINUE, PR_BLOCK, PR_COMPLETE };
51  HttpParser();
52  virtual ~HttpParser();
53
54  void reset();
55  ProcessResult Process(const char* buffer, size_t len, size_t* processed,
56                        HttpError* error);
57  bool is_valid_end_of_input() const;
58  void complete(HttpError err);
59
60  size_t GetDataRemaining() const { return data_size_; }
61
62protected:
63  ProcessResult ProcessLine(const char* line, size_t len, HttpError* error);
64
65  // HttpParser Interface
66  virtual ProcessResult ProcessLeader(const char* line, size_t len,
67                                      HttpError* error) = 0;
68  virtual ProcessResult ProcessHeader(const char* name, size_t nlen,
69                                      const char* value, size_t vlen,
70                                      HttpError* error) = 0;
71  virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size,
72                                              HttpError* error) = 0;
73  virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read,
74                                    HttpError* error) = 0;
75  virtual void OnComplete(HttpError err) = 0;
76
77private:
78  enum State {
79    ST_LEADER, ST_HEADERS,
80    ST_CHUNKSIZE, ST_CHUNKTERM, ST_TRAILERS,
81    ST_DATA, ST_COMPLETE
82  } state_;
83  bool chunked_;
84  size_t data_size_;
85};
86
87///////////////////////////////////////////////////////////////////////////////
88// IHttpNotify
89///////////////////////////////////////////////////////////////////////////////
90
91enum HttpMode { HM_NONE, HM_CONNECT, HM_RECV, HM_SEND };
92
93class IHttpNotify {
94public:
95  virtual ~IHttpNotify() {}
96  virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) = 0;
97  virtual void onHttpComplete(HttpMode mode, HttpError err) = 0;
98  virtual void onHttpClosed(HttpError err) = 0;
99};
100
101///////////////////////////////////////////////////////////////////////////////
102// HttpBase - Provides a state machine for implementing HTTP-based components.
103// Attach HttpBase to a StreamInterface which represents a bidirectional HTTP
104// stream, and then call send() or recv() to initiate sending or receiving one
105// side of an HTTP transaction.  By default, HttpBase operates as an I/O pump,
106// moving data from the HTTP stream to the HttpData object and vice versa.
107// However, it can also operate in stream mode, in which case the user of the
108// stream interface drives I/O via calls to Read().
109///////////////////////////////////////////////////////////////////////////////
110
111class HttpBase
112: private HttpParser,
113  public sigslot::has_slots<>
114{
115public:
116  HttpBase();
117  virtual ~HttpBase();
118
119  void notify(IHttpNotify* notify) { notify_ = notify; }
120  bool attach(StreamInterface* stream);
121  StreamInterface* stream() { return http_stream_; }
122  StreamInterface* detach();
123  bool isConnected() const;
124
125  void send(HttpData* data);
126  void recv(HttpData* data);
127  void abort(HttpError err);
128
129  HttpMode mode() const { return mode_; }
130
131  void set_ignore_data(bool ignore) { ignore_data_ = ignore; }
132  bool ignore_data() const { return ignore_data_; }
133
134  // Obtaining this stream puts HttpBase into stream mode until the stream
135  // is closed.  HttpBase can only expose one open stream interface at a time.
136  // Further calls will return NULL.
137  StreamInterface* GetDocumentStream();
138
139protected:
140  // Do cleanup when the http stream closes (error may be 0 for a clean
141  // shutdown), and return the error code to signal.
142  HttpError HandleStreamClose(int error);
143
144  // DoReceiveLoop acts as a data pump, pulling data from the http stream,
145  // pushing it through the HttpParser, and then populating the HttpData object
146  // based on the callbacks from the parser.  One of the most interesting
147  // callbacks is ProcessData, which provides the actual http document body.
148  // This data is then written to the HttpData::document.  As a result, data
149  // flows from the network to the document, with some incidental protocol
150  // parsing in between.
151  // Ideally, we would pass in the document* to DoReceiveLoop, to more easily
152  // support GetDocumentStream().  However, since the HttpParser is callback
153  // driven, we are forced to store the pointer somewhere until the callback
154  // is triggered.
155  // Returns true if the received document has finished, and
156  // HttpParser::complete should be called.
157  bool DoReceiveLoop(HttpError* err);
158
159  void read_and_process_data();
160  void flush_data();
161  bool queue_headers();
162  void do_complete(HttpError err = HE_NONE);
163
164  void OnHttpStreamEvent(StreamInterface* stream, int events, int error);
165  void OnDocumentEvent(StreamInterface* stream, int events, int error);
166
167  // HttpParser Interface
168  virtual ProcessResult ProcessLeader(const char* line, size_t len,
169                                      HttpError* error);
170  virtual ProcessResult ProcessHeader(const char* name, size_t nlen,
171                                      const char* value, size_t vlen,
172                                      HttpError* error);
173  virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size,
174                                              HttpError* error);
175  virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read,
176                                    HttpError* error);
177  virtual void OnComplete(HttpError err);
178
179private:
180  class DocumentStream;
181  friend class DocumentStream;
182
183  enum { kBufferSize = 32 * 1024 };
184
185  HttpMode mode_;
186  HttpData* data_;
187  IHttpNotify* notify_;
188  StreamInterface* http_stream_;
189  DocumentStream* doc_stream_;
190  char buffer_[kBufferSize];
191  size_t len_;
192
193  bool ignore_data_, chunk_data_;
194  HttpData::const_iterator header_;
195};
196
197///////////////////////////////////////////////////////////////////////////////
198
199} // namespace talk_base
200
201#endif // TALK_BASE_HTTPBASE_H__
202