1+ //
2+ // connection.cpp
3+ //
4+ // Copyright 2014 Svante Karlsson CSI AB (svante.karlsson at csi dot se)
5+ // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6+ //
7+ // Distributed under the Boost Software License, Version 1.0. (See accompanying
8+ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9+ //
10+
11+ #include < boost/algorithm/string.hpp>
12+ #include < boost/uuid/random_generator.hpp>
13+ #include < boost/uuid/uuid_io.hpp>
14+ #include < boost/lexical_cast.hpp>
15+ #include < csi_http_server/connection.h>
16+
17+ namespace csi
18+ {
19+ namespace http
20+ {
21+ static http_parser_settings s_parser_settings;
22+
23+ void connection::init_parser_settings (http_parser_settings* ps)
24+ {
25+ ps->on_message_begin = connection::on_message_begin;
26+ ps->on_url = connection::on_url;
27+ ps->on_header_field = connection::on_header_field;
28+ ps->on_header_value = connection::on_header_value;
29+ ps->on_headers_complete = connection::on_headers_complete;;
30+ ps->on_body = connection::on_body;
31+ ps->on_message_complete = connection::on_message_complete;
32+ }
33+
34+ static bool init_parser_settings ()
35+ {
36+ connection::init_parser_settings (&s_parser_settings);
37+ return true ;
38+ }
39+
40+ static bool _init_parser = init_parser_settings();
41+
42+
43+ size_t connection::s_context_count = 0 ;
44+ csi::spinlock connection::s_spinlock;
45+
46+ connection::connection (boost::asio::io_service& ios, const std::string& request_id_header) :
47+ _io_service (ios),
48+ _request_id_header_tag (request_id_header),
49+ _waiting_for_async_reply (false ),
50+ _request_complete (false ),
51+ _keep_alive (false )
52+ {
53+ {
54+ csi::spinlock::scoped_lock xx (s_spinlock);
55+ s_context_count++;
56+ }
57+ _parser.data = this ; // this is the wrong "this" since this is a baseclass... dont call any virtuals from this
58+ http_parser_init (&_parser, HTTP_REQUEST);
59+ }
60+
61+ connection::~connection ()
62+ {
63+ {
64+ csi::spinlock::scoped_lock xx (s_spinlock);
65+ s_context_count--;
66+ }
67+ }
68+
69+ size_t connection::http_parse (const char * buf, size_t len)
70+ {
71+ return http_parser_execute (&_parser, &s_parser_settings, buf, len);
72+ }
73+
74+ int connection::on_message_begin (http_parser* parser)
75+ {
76+ connection* c = (connection*)parser->data ;
77+ c->_request .reset ();
78+ c->_reply .reset ();
79+ c->_request_complete = false ;
80+ c->_last_header_was_value = false ;
81+ c->_request ._content_length = 0 ;
82+ c->_current_header_key_len = 0 ;
83+ c->_current_header_val_len = 0 ;
84+ c->_current_header_key [0 ] = 0 ;
85+ c->_current_header_val [0 ] = 0 ;
86+ return 0 ;
87+ }
88+
89+ int connection::on_url (http_parser* parser, const char *at, size_t len)
90+ {
91+ connection* c = (connection*)parser->data ;
92+ size_t nres = http_parser_parse_url (at, len, 0 , &c->_parser_url );
93+ if (!nres)
94+ {
95+ if ((1 << UF_PATH) & c->_parser_url .field_set )
96+ c->_request ._url .append (&at[c->_parser_url .field_data [UF_PATH].off ], c->_parser_url .field_data [UF_PATH].len );
97+ if ((1 << UF_QUERY) & c->_parser_url .field_set )
98+ c->_request ._query .append (&at[c->_parser_url .field_data [UF_QUERY].off ], c->_parser_url .field_data [UF_QUERY].len );
99+ }
100+ return (int )nres;
101+ }
102+
103+ int connection::on_header_field (http_parser* parser, const char *at, size_t len)
104+ {
105+ connection* c = (connection*)parser->data ;
106+
107+ if (c->_last_header_was_value )
108+ {
109+ // add current key/value to headers i request
110+ boost::algorithm::to_lower (c->_current_header_key );
111+ boost::algorithm::to_lower (c->_current_header_val );
112+ c->_request ._headers .push_back (header_t (c->_current_header_key , c->_current_header_val ));
113+ c->_current_header_key [0 ] = 0 ; // not needed
114+ c->_current_header_val [0 ] = 0 ; // not needed
115+ c->_current_header_key_len = 0 ;
116+ c->_current_header_val_len = 0 ;
117+ }
118+
119+ strncpy (&(c->_current_header_key [c->_current_header_key_len ]), at, len);
120+ c->_current_header_key_len += len;
121+
122+ // keep null terminated
123+ c->_current_header_key [c->_current_header_key_len ] = 0 ;
124+ c->_last_header_was_value = false ;
125+ return 0 ;
126+ }
127+
128+ int connection::on_header_value (http_parser* parser, const char *at, size_t len)
129+ {
130+ connection* c = (connection*)parser->data ;
131+
132+ // BUG kolla att vi inte skriver över
133+ strncpy (&(c->_current_header_val [c->_current_header_val_len ]), at, len);
134+ c->_current_header_val_len += len;
135+ // keep null terminated
136+ c->_current_header_val [c->_current_header_val_len ] = 0 ;
137+ c->_last_header_was_value = true ;
138+
139+ // should we store key/val when len = 0??
140+ // how do we detect last key/value pair
141+ // or do we need to add that later???
142+ return 0 ;
143+ }
144+
145+ int connection::on_headers_complete (http_parser* parser)
146+ {
147+ connection* c = (connection*)parser->data ;
148+
149+ if (c->_last_header_was_value )
150+ {
151+ boost::algorithm::to_lower (c->_current_header_key );
152+ boost::algorithm::to_lower (c->_current_header_val );
153+ c->_request ._headers .push_back (header_t (c->_current_header_key , c->_current_header_val ));
154+ c->_current_header_key [0 ] = 0 ; // not needed
155+ c->_current_header_val [0 ] = 0 ; // not needed
156+ c->_current_header_key_len = 0 ;
157+ c->_current_header_val_len = 0 ;
158+ }
159+
160+ c->_request ._content_length = (size_t )parser->content_length ;
161+
162+ // post and put have content....
163+ // check if it is zero on all other types...
164+ // move allocation here..
165+
166+ c->_request ._method = (csi::http::method_t ) parser->method ;
167+
168+ return 0 ;
169+ }
170+
171+ int connection::on_body (http_parser* parser, const char *at, size_t len)
172+ {
173+ connection* c = (connection*)parser->data ;
174+ c->_request ._avro_rx_buffer_stream_writer ->writeBytes ((const uint8_t *)at, len);
175+ c->_request ._avro_rx_buffer_stream_writer ->flush ();
176+ return 0 ;
177+ }
178+
179+ int connection::on_message_complete (http_parser* parser)
180+ {
181+ connection* c = (connection*)parser->data ;
182+ c->_keep_alive = (http_should_keep_alive (parser) != 0 );
183+ c->_request_complete = true ;
184+ return 0 ;
185+ }
186+ }; // namespace
187+ }; // namespace
0 commit comments