|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- ///////////////////////////////////////////////////////////////////////////////
- //
- // 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
|