-#ifndef _SQUID_SRC_HTTPPARSER_H
-#define _SQUID_SRC_HTTPPARSER_H
+#ifndef _SQUID_SRC_HTTP_ONEREQUESTPARSER_H
+#define _SQUID_SRC_HTTP_ONEREQUESTPARSER_H
#include "base/RefCount.h"
+#include "http/forward.h"
+#include "http/ProtocolVersion.h"
+#include "http/RequestMethod.h"
#include "http/StatusCode.h"
+#include "SBuf.h"
+
+namespace Http {
+namespace One {
// Parser states
#define HTTP_PARSE_NONE 0 // nothing. completely unset state.
#define HTTP_PARSE_NEW 1 // initialized, but nothing usefully parsed yet.
#define HTTP_PARSE_FIRST 2 // have parsed request first line
+#define HTTP_PARSE_MIME 3 // have located end of mime header block
#define HTTP_PARSE_DONE 99 // have done with parsing so far
/** HTTP protocol parser.
*
* Works on a raw character I/O buffer and tokenizes the content into
- * either an error state or, an HTTP procotol request major segments:
+ * either an error state or HTTP procotol major sections:
*
- * \item Request Line (method, URL, protocol, version)
- * \item Mime header block
+ * \item first-line (request-line / simple-request / status-line)
+ * \item mime-header block
*/
-class HttpParser : public RefCountable
+class Parser : public RefCountable
{
public:
- typedef RefCount<HttpParser> Pointer;
-
- HttpParser() { clear(); }
+ Parser() { clear(); }
/** Initialize a new parser.
- * Presenting it a buffer to work on and the current length of available
- * data.
+ * Presenting it a buffer to work on and the current length of available data.
* NOTE: This is *not* the buffer size, just the parse-able data length.
* The parse routines may be called again later with more data.
*/
- HttpParser(const char *aBuf, int len) { reset(aBuf,len); };
+ Parser(const char *aBuf, int len) { reset(aBuf,len); }
/// Set this parser back to a default state.
/// Will DROP any reference to a buffer (does not free).
- void clear();
+ virtual void clear();
/// Reset the parser for use on a new buffer.
void reset(const char *aBuf, int len);
+ /** Adjust parser state to account for a buffer shift of n bytes.
+ *
+ * The leftmost n bytes bytes have been dropped and all other
+ * bytes shifted left n positions.
+ */
+ virtual void noteBufferShift(int64_t n) = 0;
+
/** Whether the parser is already done processing the buffer.
* Use to determine between incomplete data and errors results
- * from the parse methods.
+ * from the parse.
*/
bool isDone() const {return completedState_==HTTP_PARSE_DONE;}
- /// size in bytes of the first line (request-line)
- /// including CRLF terminator
- int64_t firstLineSize() const {return req.end - req.start + 1;}
+ /// number of bytes in buffer before the message
+ virtual int64_t messageOffset() const = 0;
+
+ /// size in bytes of the first line including CRLF terminator
+ virtual int64_t firstLineSize() const = 0;
- /// size in bytes of the message headers including CRLF terminator
- /// but excluding request-line bytes
- int64_t headerBlockSize() const {return hdr_end - hdr_start + 1;}
+ /// size in bytes of the message headers including CRLF terminator(s)
+ /// but excluding first-line bytes
+ int64_t headerBlockSize() const {return mimeHeaderBlock_.length();}
- /// size in bytes of HTTP message block, includes request-line and mime headers
+ /// size in bytes of HTTP message block, includes first-line and mime headers
/// excludes any body/entity/payload bytes
- int64_t messageHeaderSize() const {return hdr_end - req.start + 1;}
+ /// excludes any garbage prefix before the first-line
+ int64_t messageHeaderSize() const {return firstLineSize() + headerBlockSize();}
- /// buffer containing HTTP mime headers
- // convert to SBuf
- const char *rawHeaderBuf() {return buf + hdr_start;}
+ /// buffer containing HTTP mime headers, excluding message first-line.
+ const char *rawHeaderBuf() {return mimeHeaderBlock_.c_str();}
- /** Attempt to parse a request.
- * \return true if a valid request was parsed.
- * \note Use isDone() method to determine between incomplete parse and errors.
- */
- // TODO: parse more than just the request-line
- bool parseRequest();
+ /// attempt to parse a message from the buffer
+ virtual bool parse() = 0;
+
+ /// the protocol label for this message
+ const AnyP::ProtocolVersion & messageProtocol() const {return msgProtocol_;}
/**
- * Attempt to parse the first line of a new request message.
- *
- * Governed by:
- * RFC 1945 section 5.1
- * RFC 2616 section 5.1
- *
- * Parsing state is stored between calls. However the current implementation
- * begins parsing from scratch on every call.
- * The return value tells you whether the parsing state fields are valid or not.
- *
- * \retval -1 an error occurred. request_parse_status indicates HTTP status result.
- * \retval 1 successful parse. member fields contain the request-line items
- * \retval 0 more data is needed to complete the parse
+ * \return A pointer to a field-value of the first matching field-name, or NULL.
*/
- int parseRequestFirstLine();
+ char *getHeaderField(const char *name);
public:
const char *buf;
int bufsiz;
- /// Offsets for pieces of the (HTTP request) Request-Line as per RFC 2616
- struct request_offsets {
- int start, end;
- int m_start, m_end; // method
- int u_start, u_end; // url
- int v_start, v_end; // version (full text)
- int v_maj, v_min; // version numerics
- } req;
+protected:
+ /// what stage the parser is currently up to
+ uint8_t completedState_;
- // Offsets for pieces of the MiME Header segment
- int hdr_start, hdr_end;
+ /// what protocol label has been found in the first line
+ AnyP::ProtocolVersion msgProtocol_;
- // TODO: Offsets for pieces of the (HTTP reply) Status-Line as per RFC 2616
+ /// byte offset for non-parsed region of the buffer
+ size_t parseOffset_;
+
+ /// buffer holding the mime headers
+ SBuf mimeHeaderBlock_;
+};
+
+/** HTTP protocol request parser.
+ *
+ * Works on a raw character I/O buffer and tokenizes the content into
+ * either an error state or, an HTTP procotol request major segments:
+ *
+ * \item Request Line (method, URL, protocol, version)
+ * \item Mime header block
+ */
+class RequestParser : public Http1::Parser
+{
+public:
+ /* Http::One::Parser API */
+ RequestParser() : Parser() {}
+ RequestParser(const char *aBuf, int len) : Parser(aBuf, len) {}
+ virtual void clear();
+ virtual void noteBufferShift(int64_t n);
+ virtual int64_t messageOffset() const {return req.start;}
+ virtual int64_t firstLineSize() const {return req.end - req.start + 1;}
+ virtual bool parse();
+
+ /// the HTTP method if this is a request message
+ const HttpRequestMethod & method() const {return method_;}
+
+ /// the request-line URI if this is a request message, or an empty string.
+ const SBuf &requestUri() const {return uri_;}
/** HTTP status code to be used on the invalid-request error page
* Http::scNone indicates incomplete parse, Http::scOkay indicates no error.
Http::StatusCode request_parse_status;
private:
- /// byte offset for non-parsed region of the buffer
- size_t parseOffset_;
+ bool skipGarbageLines();
+ int parseRequestFirstLine();
- /// what stage the parser is currently up to
- uint8_t completedState_;
+ /// Offsets for pieces of the (HTTP request) Request-Line as per RFC 2616
+ struct request_offsets {
+ int start, end;
+ int m_start, m_end; // method
+ int u_start, u_end; // url
+ int v_start, v_end; // version (full text)
+ } req;
+
+ /// what request method has been found on the first line
+ HttpRequestMethod method_;
+
+ /// raw copy of the origina client reqeust-line URI field
+ SBuf uri_;
};
-#endif /* _SQUID_SRC_HTTPPARSER_H */
+} // namespace One
+} // namespace Http
+
+#endif /* _SQUID_SRC_HTTP_HTTP1PARSER_H */