|
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
- //
- // See accompanying file COPYING.TXT file for licensing details.
- //
- ///////////////////////////////////////////////////////////////////////////////
- #ifndef CPPCMS_HTTP_PARSER_H
- #define CPPCMS_HTTP_PARSER_H
- #include "http_protocol.h"
- #include <vector>
- #include <string>
- #include <stack>
-
- #ifdef getc
- #undef getc
- #endif
-
- namespace cppcms {
- namespace http {
- namespace impl {
-
-
- class parser {
- enum {
- idle,
- input_observed,
- last_lf_exptected,
- lf_exptected,
- space_or_other_exptected,
- quote_expected,
- pass_quote_exptected,
- closing_bracket_expected,
- pass_closing_bracket_expected
- } state_;
-
- unsigned bracket_counter_;
-
- std::vector<char> *body_;
- unsigned *body_ptr_;
- char const **pbase_,**pptr_,**epptr_;
- std::stack<char> ungot_;
-
-
- // Non copyable
-
- parser(parser const &);
- parser const &operator=(parser const &);
- protected:
- inline int getc()
- {
- if(!ungot_.empty()) {
- unsigned char r=ungot_.top();
- ungot_.pop();
- return r;
- }
- if(body_) {
- if(*body_ptr_ < body_->size()) {
- return (unsigned char)(*body_)[(*body_ptr_)++];
- }
- else {
- body_->clear();
- *body_ptr_=0;
- return -1;
- }
- }
- else {
- if(*pptr_ != *epptr_) {
- unsigned char c = *(*pptr_)++;
- return c;
- }
- else {
- return -1;
- }
- }
- }
- inline void ungetc(int c)
- {
- if(body_) {
- if(*body_ptr_ > 0)
- (*body_ptr_)--;
- else
- ungot_.push(c);
- }
- else {
- if(*pbase_!=*pptr_)
- (*pptr_)--;
- else
- ungot_.push(c);
-
- }
- }
-
- public:
- std::string header_;
-
- parser(std::vector<char> &body,unsigned &body_ptr) :
- state_(idle),
- bracket_counter_(0),
- body_(&body),
- body_ptr_(&body_ptr),
- pbase_(0),
- pptr_(0),
- epptr_(0)
- {
- header_.reserve(32);
- }
- parser(char const *&pbase,char const *&pptr,char const *&epptr) :
- state_(idle),
- bracket_counter_(0),
- body_(0),
- body_ptr_(0),
- pbase_(&pbase),
- pptr_(&pptr),
- epptr_(&epptr)
-
- {
- header_.reserve(32);
- }
- void reset()
- {
- state_ = idle;
- bracket_counter_ = 0;
- header_.clear();
- }
- enum { more_data, got_header, end_of_headers , error_observerd };
- int step()
- {
- #ifdef DEBUG_HTTP_PARSER
- static char const *states[]= {
- "idle",
- "input_observed",
- "last_lf_exptected",
- "lf_exptected",
- "space_or_other_exptected",
- "quote_expected",
- "pass_quote_exptected",
- "closing_bracket_expected",
- "pass_closing_bracket_expected"
- };
- #endif
- for(;;) {
- int c=getc();
- #if defined DEBUG_HTTP_PARSER
- std::cerr<<"Step("<<body_ptr_<<":"<<body_.size()<<": "<<std::flush;
- if(c>=32)
- std::cerr<<"["<<char(c)<<"] "<<states[state_]<<std::endl;
- else
- std::cerr<<c<<" "<<states[state_]<<std::endl;
- #endif
-
- if(c<0)
- return more_data;
-
-
- switch(state_) {
- case idle:
- header_.clear();
- switch(c) {
- case '\r':
- state_=last_lf_exptected;
- break;
- case '"':
- state_=quote_expected;
- break;
- case '(':
- state_=closing_bracket_expected;
- bracket_counter_++;
- break;
- default:
- state_=input_observed;
- }
- break;
- case last_lf_exptected:
- if(c!='\n') return error_observerd;
- header_.clear();
- return end_of_headers;
- case lf_exptected:
- if(c!='\n') return error_observerd;
- state_=space_or_other_exptected;
- break;
- case space_or_other_exptected:
- if(c==' ' || c=='\t') {
- // Convert LWS to space as required by
- // RFC, so remove last CRLF
- header_.resize(header_.size() - 2);
- state_=input_observed;
- break;
- }
- ungetc(c);
- header_.resize(header_.size()-2);
- state_=idle;
- #ifdef DEBUG_HTTP_PARSER
- std::cerr<<"["<<header_<<"]"<<std::endl;
- #endif
- return got_header;
- case input_observed:
- switch(c) {
- case '\r':
- state_=lf_exptected;
- break;
- case '"':
- state_=quote_expected;
- break;
- case '(':
- state_=closing_bracket_expected;
- bracket_counter_++;
- break;
- default:
- state_=input_observed;
- }
- break;
- case quote_expected:
- switch(c) {
- case '"':
- state_=input_observed;
- break;
- case '\\':
- state_=pass_quote_exptected;
- break;
- }
- break;
- case pass_quote_exptected:
- if(c < 0 || c >=127)
- return error_observerd;
- state_=quote_expected;
- break;
- case closing_bracket_expected:
- switch(c) {
- case ')':
- bracket_counter_--;
- if(bracket_counter_==0)
- state_=input_observed;
- break;
- case '\\':
- state_=pass_closing_bracket_expected;
- break;
- }
- break;
- case pass_closing_bracket_expected:
- if(c < 0 || c >=127)
- return error_observerd;
- state_=closing_bracket_expected;
- break;
- }
-
- header_+=char(c);
-
- /* switch(state_) {
- case idle:
- case input_observed:
- case last_lf_exptected:
- case lf_exptected:
- case space_or_other_exptected:
- if(separator(c)) {
- parsed_.push_back(element_type(c,std::string()));
- }
- else if(0x20 <= c && c<=0x7E) {
- if(parsed_.empty() || parsed_.back().first != token_element) {
- parsed.push_back(element_type(token_element,std::string()));
- }
- parsed.back().second+=c;
- }
- break;
- default:
- ; // Nothing
- }*/
- }
- }
-
- }; // class parser
-
-
- }}} // cppcms::http::impl
-
- #endif
|