ext/libcouchbase/src/lcbht/lcbht.h in libcouchbase-0.3.3 vs ext/libcouchbase/src/lcbht/lcbht.h in libcouchbase-1.0.0
- old
+ new
@@ -17,19 +17,16 @@
#ifndef LCB_HTTP_H
#define LCB_HTTP_H
#include <libcouchbase/couchbase.h>
-#include "simplestring.h"
-#include "sllist.h"
+#include "contrib/http_parser/http_parser.h"
+#include <list>
+#include <string>
+
struct lcb_settings_st;
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/**
* @file
* HTTP Response parsing.
*
* This file provides HTTP/1.0 compatible response parsing semantics, supporting
@@ -37,163 +34,177 @@
*
* Specifically this may be used to parse incoming HTTP streams into a single
* body.
*/
-/** Response state */
-typedef enum {
- LCBHT_S_HTSTATUS = 1 << 0, /**< Have HTTP status */
- LCBHT_S_HEADER = 1 << 1, /**< Have HTTP header */
- LCBHT_S_BODY = 1 << 2, /**< Have HTTP body */
- LCBHT_S_DONE = 1 << 3, /**< Have a full message */
+namespace lcb {
+namespace htparse {
- /**Have a parse error. Note this is not the same as a HTTP error */
- LCBHT_S_ERROR = 1 << 4
-} lcbht_RESPSTATE;
-typedef struct {
- sllist_node slnode; /**< Next header in list */
- const char *key;
- const char *value;
- lcb_string buf_; /**< Storage for the key and value */
-} lcbht_MIMEHDR;
+struct MimeHeader {
+ std::string key;
+ std::string value;
+};
-typedef struct {
+struct Response {
+ void clear() {
+ status = 0;
+ state = 0;
+ headers.clear();
+ body.clear();
+ }
+
+ /**
+ * Get a header value for a key
+ * @param response The response
+ * @param key The key to look up
+ * @return A string containing the value. If the header has no value then the
+ * empty string will be returned. If the header does not exist NULL will be
+ * returned.
+ */
+ const MimeHeader* get_header(const std::string& key) const;
+
+ /**
+ * Get a header value for a key
+ * @param key The key to look up
+ * @return A string containing the value. If the header has no value then the
+ * empty string will be returned. If the header does not exist NULL will be
+ * returned.
+ */
+ const char *get_header_value(const std::string& key) const {
+ const MimeHeader *header = get_header(key);
+ if (header) {
+ return header->value.c_str();
+ }
+ return NULL;
+ }
+
unsigned short status; /**< HTTP Status code */
- lcbht_RESPSTATE state;
- sllist_root headers; /**< List of response headers */
- lcb_string body; /**< Body */
-} lcbht_RESPONSE;
+ unsigned state;
+ typedef std::list<MimeHeader> HeaderList;
+ HeaderList headers;
+ std::string body; /**< Body */
+};
-typedef struct lcbht_PARSER *lcbht_pPARSER;
+class Parser : private http_parser {
+public:
+ /**
+ * Initialize the parser object
+ * @param settings the settings structure used for logging
+ */
+ Parser(lcb_settings_st*);
+ ~Parser();
-/**
- * Initialize the parser object
- * @param settings the settings structure used for logging
- * @return a new parser object
- */
-lcbht_pPARSER
-lcbht_new(struct lcb_settings_st *settings);
+ /** Response state */
+ enum State {
+ S_NONE = 0,
+ S_HTSTATUS = 1 << 0, /**< Have HTTP status */
+ S_HEADER = 1 << 1, /**< Have HTTP header */
+ S_BODY = 1 << 2, /**< Have HTTP body */
+ S_DONE = 1 << 3, /**< Have a full message */
-/** Free the parser object */
-void
-lcbht_free(lcbht_pPARSER);
+ /**Have a parse error. Note this is not the same as a HTTP error */
+ S_ERROR = 1 << 4
+ };
-void
-lcbht_reset(lcbht_pPARSER);
+ /**
+ * Parse incoming data into a message
+ * @param data Pointer to new data
+ * @param ndata Size of the data
+ *
+ * @return The current state of the parser. If `state & LCBHT_S_DONE` then
+ * the current response should be handled before continuing.
+ * If `state & LCBHT_S_ERROR` then there was an error parsing the contents
+ * as it violated the HTTP protocol.
+ */
+ unsigned parse(const void *data, size_t ndata);
-/**
- * Parse incoming data into a message
- * @param parser The parser
- * @param data Pointer to new data
- * @param ndata Size of the data
- *
- * @return The current state of the parser. If `state & LCBHT_S_DONE` then
- * the current response should be handled before continuing.
- * If `state & LCBHT_S_ERROR` then there was an error parsing the contents
- * as it violated the HTTP protocol.
- */
-lcbht_RESPSTATE
-lcbht_parse(lcbht_pPARSER parser, const void *data, unsigned ndata);
+ /**
+ * Parse incoming data without buffering
+ * @param data The data to parse
+ * @param ndata Length of the data
+ * @param[out] nused How much of the data was actually consumed
+ * @param[out] nbody Size of the body pointer
+ * @param[out] pbody a pointer for the body
+ *
+ * @return See lcbht_set_bufmode for the meaning of this value
+ *
+ * @note It is not an error if `pbody` is NULL. It may mean that the parse state
+ * is still within the headers and there is no body to parse yet.
+ *
+ * This function is intended to be used in a loop, until there is no input
+ * remaining. The use of the `nused` pointer is to determine by how much the
+ * `data` pointer should be incremented (and the `ndata` decremented) for the
+ * next call. When this function returns with a non-error status, `pbody`
+ * will contain a pointer to a buffer of data (but see note above) which can
+ * then be processed by the application.
+ *
+ * @code{.c++}
+ * char **body, *input;
+ * unsigned inlen = get_input_len(), nused, bodylen;
+ * unsigned res;
+ * do {
+ * res = parser->parse_ex(input, inlen, &nused, &nbody, &body);
+ * if (res & Parser::S_ERROR) {
+ * // handle error
+ * break;
+ * }
+ * if (nbody) {
+ * // handle body
+ * }
+ * input += nused;
+ * inlen -= nused;
+ * } while (!(res & Parser::S_DONE));
+ * @endcode
+ */
+ unsigned parse_ex(const void *data, unsigned ndata,
+ unsigned* nused, unsigned *nbody, const char **pbody);
-/**
- * Parse incoming data without buffering
- * @param parser The parser to use
- * @param data The data to parse
- * @param ndata Length of the data
- * @param[out] nused How much of the data was actually consumed
- * @param[out] nbody Size of the body pointer
- * @param[out] pbody a pointer for the body
- *
- * @return See lcbht_set_bufmode for the meaning of this value
- *
- * @note It is not an error if `pbody` is NULL. It may mean that the parse state
- * is still within the headers and there is no body to parse yet.
- *
- * This function is intended to be used in a loop, until there is no input
- * remaining. The use of the `nused` pointer is to determine by how much the
- * `data` pointer should be incremented (and the `ndata` decremented) for the
- * next call. When this function returns with a non-error status, `pbody`
- * will contain a pointer to a buffer of data (but see note above) which can
- * then be processed by the application.
- *
- * @code{.c}
- * char **body, *input;
- * unsigned inlen = get_input_len(), nused, bodylen;
- * lcbht_RESPSTATE res;
- * do {
- * res = lcbht_parse_ex(parser, input, inlen, &nused, &nbody, &body);
- * if (res & LCBHT_S_ERROR) {
- * // handle error
- * break;
- * }
- * if (nbody) {
- * // handle body
- * }
- * input += nused;
- * inlen -= nused;
- * } while (!(res & LCBHT_S_DONE));
- * @endcode
- */
-lcbht_RESPSTATE
-lcbht_parse_ex(lcbht_pPARSER parser, const void *data, unsigned ndata,
- unsigned *nused, unsigned *nbody, const char **pbody);
+ /**
+ * Obtain the current response being processed.
+ * @return a reference to a response object. The response object is only valid
+ * until the next call into another parser API
+ */
+ Response& get_cur_response() {
+ return resp;
+ }
+ /**
+ * Determine whether HTTP/1.1 keepalive is enabled on the connection
+ * @return true if keepalive is enabled, false otherwise.
+ */
+ bool can_keepalive() const;
-/**
- * Obtain the current response being processed.
- * @param parser The parser
- * @return a pointer to a response object. The response object is only valid
- * until the next call into another parser API
- */
-lcbht_RESPONSE *
-lcbht_get_response(lcbht_pPARSER parser);
+ void reset();
-/**
- * Determine whether HTTP/1.1 keepalive is enabled on the connection
- * @param parser The parser
- * @return true if keepalive is enabled, false otherwise.
- */
-int
-lcbht_can_keepalive(lcbht_pPARSER parser);
+ // Callbacks:
+ inline int on_hdr_key(const char *, size_t);
+ inline int on_hdr_value(const char *, size_t);
+ inline int on_hdr_done();
+ inline int on_body(const char *, size_t);
+ inline int on_msg_done();
-/**
- * Clear the response object
- * @param resp the response to clear
- */
-void
-lcbht_clear_response(lcbht_RESPONSE *resp);
+ static Parser* from_htp(http_parser *p) {
+ return static_cast<Parser*>(p);
+ }
-/**
- * Get a header value for a key
- * @param response The response
- * @param key The key to look up
- * @return A string containing the value. If the header has no value then the
- * empty string will be returned. If the header does not exist NULL will be
- * returned.
- */
-const char *
-lcbht_get_resphdr(const lcbht_RESPONSE *response, const char *key);
+private:
+ Response resp;
+ lcb_settings_st *settings;
-/**
- * Return a list of headers
- * @param response The response
- * @return A list of headers. Iterate over this value like so:
- * @code{.c}
- * char **hdrlist = lcbht_make_resphdrlist(response);
- * for (char **cur = hdrlist; *cur; cur += 2) {
- * char *key = cur[0];
- * char *value = cur[1];
- * // do something
- * free(key);
- * free(value);
- * }
- * free(hdrlist);
- * @endcode
- */
-char **
-lcbht_make_resphdrlist(lcbht_RESPONSE *response);
+ enum last_call_type {
+ CB_NONE, CB_HDR_KEY, CB_HDR_VALUE,
+ CB_HDR_DONE, CB_BODY, CB_MSG_DONE
+ };
+ last_call_type lastcall;
-#ifdef __cplusplus
-}
-#endif
+ /* For parse_ex */
+ const char *last_body;
+ unsigned last_bodylen;
+
+ bool paused;
+ bool is_ex;
+};
+
+} // namespace htparse
+} // namespace lcb
#endif