Merge branch 'master' of http://skoegl.net/uni/numpty
[numtypysics.git] / happyhttp.h
blob81cf56c7dfc636e15d60a92e548eea3fceb7be57
1 /*
2 * HappyHTTP - a simple HTTP library
3 * Version 0.1
4 *
5 * Copyright (c) 2006 Ben Campbell
7 * This software is provided 'as-is', without any express or implied
8 * warranty. In no event will the authors be held liable for any damages
9 * arising from the use of this software.
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software. If you use this software in a
17 * product, an acknowledgment in the product documentation would be
18 * appreciated but is not required.
20 * 2. Altered source versions must be plainly marked as such, and must not
21 * be misrepresented as being the original software.
23 * 3. This notice may not be removed or altered from any source distribution.
28 #ifndef HAPPYHTTP_H
29 #define HAPPYHTTP_H
32 #include <string>
33 #include <map>
34 #include <vector>
35 #include <deque>
40 // forward decl
41 struct in_addr;
43 namespace happyhttp
47 class Response;
49 // Helper Functions
50 void BailOnSocketError( const char* context );
51 struct in_addr *atoaddr( const char* address);
54 typedef void (*ResponseBegin_CB)( const Response* r, void* userdata );
55 typedef void (*ResponseData_CB)( const Response* r, void* userdata, const unsigned char* data, int numbytes );
56 typedef void (*ResponseComplete_CB)( const Response* r, void* userdata );
59 // HTTP status codes
60 enum {
61 // 1xx informational
62 CONTINUE = 100,
63 SWITCHING_PROTOCOLS = 101,
64 PROCESSING = 102,
66 // 2xx successful
67 OK = 200,
68 CREATED = 201,
69 ACCEPTED = 202,
70 NON_AUTHORITATIVE_INFORMATION = 203,
71 NO_CONTENT = 204,
72 RESET_CONTENT = 205,
73 PARTIAL_CONTENT = 206,
74 MULTI_STATUS = 207,
75 IM_USED = 226,
77 // 3xx redirection
78 MULTIPLE_CHOICES = 300,
79 MOVED_PERMANENTLY = 301,
80 FOUND = 302,
81 SEE_OTHER = 303,
82 NOT_MODIFIED = 304,
83 USE_PROXY = 305,
84 TEMPORARY_REDIRECT = 307,
86 // 4xx client error
87 BAD_REQUEST = 400,
88 UNAUTHORIZED = 401,
89 PAYMENT_REQUIRED = 402,
90 FORBIDDEN = 403,
91 NOT_FOUND = 404,
92 METHOD_NOT_ALLOWED = 405,
93 NOT_ACCEPTABLE = 406,
94 PROXY_AUTHENTICATION_REQUIRED = 407,
95 REQUEST_TIMEOUT = 408,
96 CONFLICT = 409,
97 GONE = 410,
98 LENGTH_REQUIRED = 411,
99 PRECONDITION_FAILED = 412,
100 REQUEST_ENTITY_TOO_LARGE = 413,
101 REQUEST_URI_TOO_LONG = 414,
102 UNSUPPORTED_MEDIA_TYPE = 415,
103 REQUESTED_RANGE_NOT_SATISFIABLE = 416,
104 EXPECTATION_FAILED = 417,
105 UNPROCESSABLE_ENTITY = 422,
106 LOCKED = 423,
107 FAILED_DEPENDENCY = 424,
108 UPGRADE_REQUIRED = 426,
110 // 5xx server error
111 INTERNAL_SERVER_ERROR = 500,
112 NOT_IMPLEMENTED = 501,
113 BAD_GATEWAY = 502,
114 SERVICE_UNAVAILABLE = 503,
115 GATEWAY_TIMEOUT = 504,
116 HTTP_VERSION_NOT_SUPPORTED = 505,
117 INSUFFICIENT_STORAGE = 507,
118 NOT_EXTENDED = 510,
123 // Exception class
125 class Wobbly
127 public:
128 Wobbly( const char* fmt, ... );
129 const char* what() const
130 { return m_Message; }
131 protected:
132 enum { MAXLEN=256 };
133 char m_Message[ MAXLEN ];
138 //-------------------------------------------------
139 // Connection
141 // Handles the socket connection, issuing of requests and managing
142 // responses.
143 // ------------------------------------------------
145 class Connection
147 friend class Response;
148 public:
149 // doesn't connect immediately
150 Connection( const char* host, int port );
151 ~Connection();
153 // Set up the response handling callbacks. These will be invoked during
154 // calls to pump().
155 // begincb - called when the responses headers have been received
156 // datacb - called repeatedly to handle body data
157 // completecb - response is completed
158 // userdata is passed as a param to all callbacks.
159 void setcallbacks(
160 ResponseBegin_CB begincb,
161 ResponseData_CB datacb,
162 ResponseComplete_CB completecb,
163 void* userdata );
165 // Don't need to call connect() explicitly as issuing a request will
166 // call it automatically if needed.
167 // But it could block (for name lookup etc), so you might prefer to
168 // call it in advance.
169 void connect();
171 // close connection, discarding any pending requests.
172 void close();
174 // Update the connection (non-blocking)
175 // Just keep calling this regularly to service outstanding requests.
176 void pump();
178 // any requests still outstanding?
179 bool outstanding() const
180 { return !m_Outstanding.empty(); }
182 // ---------------------------
183 // high-level request interface
184 // ---------------------------
186 // method is "GET", "POST" etc...
187 // url is only path part: eg "/index.html"
188 // headers is array of name/value pairs, terminated by a null-ptr
189 // body & bodysize specify body data of request (eg values for a form)
190 void request( const char* method, const char* url, const char* headers[]=0,
191 const unsigned char* body=0, int bodysize=0 );
193 // ---------------------------
194 // low-level request interface
195 // ---------------------------
197 // begin request
198 // method is "GET", "POST" etc...
199 // url is only path part: eg "/index.html"
200 void putrequest( const char* method, const char* url );
202 // Add a header to the request (call after putrequest() )
203 void putheader( const char* header, const char* value );
204 void putheader( const char* header, int numericvalue ); // alternate version
206 // Finished adding headers, issue the request.
207 void endheaders();
209 // send body data if any.
210 // To be called after endheaders()
211 void send( const unsigned char* buf, int numbytes );
213 protected:
214 // some bits of implementation exposed to Response class
216 // callbacks
217 ResponseBegin_CB m_ResponseBeginCB;
218 ResponseData_CB m_ResponseDataCB;
219 ResponseComplete_CB m_ResponseCompleteCB;
220 void* m_UserData;
222 private:
223 enum { IDLE, REQ_STARTED, REQ_SENT } m_State;
224 std::string m_Host;
225 int m_Port;
226 int m_Sock;
227 std::vector< std::string > m_Buffer; // lines of request
229 std::deque< Response* > m_Outstanding; // responses for outstanding requests
237 //-------------------------------------------------
238 // Response
240 // Handles parsing of response data.
241 // ------------------------------------------------
244 class Response
246 friend class Connection;
247 public:
249 // retrieve a header (returns 0 if not present)
250 const char* getheader( const char* name ) const;
252 bool completed() const
253 { return m_State == COMPLETE; }
256 // get the HTTP status code
257 int getstatus() const;
259 // get the HTTP response reason string
260 const char* getreason() const;
262 // true if connection is expected to close after this response.
263 bool willclose() const
264 { return m_WillClose; }
265 protected:
266 // interface used by Connection
268 // only Connection creates Responses.
269 Response( const char* method, Connection& conn );
271 // pump some data in for processing.
272 // Returns the number of bytes used.
273 // Will always return 0 when response is complete.
274 int pump( const unsigned char* data, int datasize );
276 // tell response that connection has closed
277 void notifyconnectionclosed();
279 private:
280 enum {
281 STATUSLINE, // start here. status line is first line of response.
282 HEADERS, // reading in header lines
283 BODY, // waiting for some body data (all or a chunk)
284 CHUNKLEN, // expecting a chunk length indicator (in hex)
285 CHUNKEND, // got the chunk, now expecting a trailing blank line
286 TRAILERS, // reading trailers after body.
287 COMPLETE, // response is complete!
288 } m_State;
290 Connection& m_Connection; // to access callback ptrs
291 std::string m_Method; // req method: "GET", "POST" etc...
293 // status line
294 std::string m_VersionString; // HTTP-Version
295 int m_Version; // 10: HTTP/1.0 11: HTTP/1.x (where x>=1)
296 int m_Status; // Status-Code
297 std::string m_Reason; // Reason-Phrase
299 // header/value pairs
300 std::map<std::string,std::string> m_Headers;
302 int m_BytesRead; // body bytes read so far
303 bool m_Chunked; // response is chunked?
304 int m_ChunkLeft; // bytes left in current chunk
305 int m_Length; // -1 if unknown
306 bool m_WillClose; // connection will close at response end?
308 std::string m_LineBuf; // line accumulation for states that want it
309 std::string m_HeaderAccum; // accumulation buffer for headers
312 void FlushHeader();
313 void ProcessStatusLine( std::string const& line );
314 void ProcessHeaderLine( std::string const& line );
315 void ProcessTrailerLine( std::string const& line );
316 void ProcessChunkLenLine( std::string const& line );
318 int ProcessDataChunked( const unsigned char* data, int count );
319 int ProcessDataNonChunked( const unsigned char* data, int count );
321 void BeginBody();
322 bool CheckClose();
323 void Finish();
328 } // end namespace happyhttp
331 #endif // HAPPYHTTP_H