Skip to content
This repository was archived by the owner on Dec 5, 2017. It is now read-only.

Commit ae740df

Browse files
committed
initial version after lib split
0 parents  commit ae740df

36 files changed

+2672
-0
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
INCLUDE(${CMAKE_SOURCE_DIR}/../build-scripts/CMakeDependencies.txt)
3+
4+
set(EXT_LIBS ${CSI_HTTP_SERVER_LIBS})
5+
6+
#compile a http parser library from third party source
7+
ADD_LIBRARY(csi-http-parser STATIC ${HTTP_PARSER_PATH}/http_parser.h ${HTTP_PARSER_PATH}/http_parser.c)
8+
9+
add_subdirectory(csi_http_server)
10+
add_subdirectory(samples)

LICENSE.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Boost Software License - Version 1.0 - August 17th, 2003
2+
3+
Permission is hereby granted, free of charge, to any person or organization
4+
obtaining a copy of the software and accompanying documentation covered by
5+
this license (the "Software") to use, reproduce, display, distribute,
6+
execute, and transmit the Software, and to prepare derivative works of the
7+
Software, and to permit third-parties to whom the Software is furnished to
8+
do so, all subject to the following:
9+
10+
The copyright notices in the Software and this entire statement, including
11+
the above license grant, this restriction and the following disclaimer,
12+
must be included in all copies of the Software, in whole or in part, and
13+
all derivative works of the Software, unless such copies or derivative
14+
works are solely in the form of machine-executable object code generated by
15+
a source language processor.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
csi-http
2+
========
3+
4+
async http client and server library written in C++11, builtin support for Apache Avro encoding
5+
- syncronous client based on libcurl and boost ASIO
6+
- asyncronous client based on libcurl and boost ASIO
7+
- asyncronous high performance server based on Joyents http_parser and boost ASIO
8+
- generic GET, PUT, POST
9+
- REST calls using avro binary and json encoded payloads (using POST)
10+
- REST calls using "generic" json encoded payloads (with optional json-spirit library)
11+
- HTTP 1.1, specifically supports connection:keep-alive
12+
- support for HTTPS using OpenSSL
13+
14+
Missing:
15+
- no support for avro rpc (REST calls with avro payload supported)
16+
17+
Platforms:
18+
- Windows, Visual studio 2013
19+
- Linux, GCC
20+
- Raspberry Pi, GCC
21+
22+
23+
Building
24+
see
25+
https://github.com/bitbouncer/csi-build-scripts
26+
27+
28+
License:
29+
- Boost Software License, Version 1.0.
30+
31+
32+
33+
34+
35+
36+
37+
38+
39+
40+

csi_http_server/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
SET(LIB_SRCS
2+
utils/uri_pattern.h
3+
utils/uri_pattern.cpp
4+
connection.h
5+
connection.cpp
6+
header.h
7+
reply.h
8+
reply.cpp
9+
request.h
10+
request.cpp
11+
server.h
12+
http_server.h
13+
http_server.cpp
14+
http_connection.h
15+
http_connection.cpp
16+
https_server.h
17+
https_server.cpp
18+
https_connection.h
19+
https_connection.cpp
20+
)
21+
22+
add_library (csi-http-server STATIC ${LIB_SRCS})
23+

csi_http_server/connection.cpp

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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

csi_http_server/connection.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// connection.h
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+
#pragma once
12+
13+
#include <boost/array.hpp>
14+
#include <boost/asio.hpp>
15+
#include "request.h"
16+
#include "reply.h"
17+
#include <http_parser.h>
18+
#include <csi_http_common/spinlock.h>
19+
20+
namespace csi
21+
{
22+
namespace http
23+
{
24+
class connection : private boost::noncopyable
25+
{
26+
enum { MAX_HEADER_SIZE = 4096 };
27+
28+
public:
29+
connection(boost::asio::io_service& ios, const std::string& request_id_header); // server agent
30+
virtual ~connection();
31+
32+
virtual void wait_for_async_reply() = 0;
33+
virtual void notify_async_reply_done() = 0;
34+
35+
inline const request_t& request() const { return _request; }
36+
inline reply_t& reply() { return _reply; }
37+
//const std::string& request_id() const;
38+
inline bool waiting_for_reply() const { return _waiting_for_async_reply; }
39+
size_t http_parse(const char* at, size_t len);
40+
static void init_parser_settings(http_parser_settings* ps);
41+
inline static size_t connection_count() { return s_context_count; }
42+
protected:
43+
virtual void send_reply() = 0;
44+
inline bool request_complete() const { return _request_complete; }
45+
inline bool keep_alive() const { return _keep_alive; }
46+
inline bool upgrade() const { return (_parser.upgrade > 0); }
47+
static int on_message_begin(http_parser*);
48+
static int on_url(http_parser*, const char *at, size_t len);
49+
static int on_header_field(http_parser*, const char *at, size_t len);
50+
static int on_header_value(http_parser*, const char *_last_header_was_valueat, size_t len);
51+
static int on_headers_complete(http_parser*);
52+
static int on_body(http_parser*, const char *_last_header_was_valueat, size_t len);
53+
static int on_message_complete(http_parser*);
54+
55+
boost::asio::io_service& _io_service;
56+
const std::string _request_id_header_tag;
57+
http_parser _parser;
58+
boost::array<char, 8192> _buffer; /// Buffer for incoming data.
59+
request_t _request;
60+
reply_t _reply;
61+
bool _last_header_was_value;
62+
char _current_header_key[MAX_HEADER_SIZE];
63+
char _current_header_val[MAX_HEADER_SIZE];
64+
size_t _current_header_key_len;
65+
size_t _current_header_val_len;
66+
http_parser_url _parser_url;
67+
bool _request_complete;
68+
bool _keep_alive;
69+
mutable std::string _request_id; /* assigned a uuid if needed and none was given in the request */
70+
bool _waiting_for_async_reply;
71+
static csi::spinlock s_spinlock;
72+
static size_t s_context_count;
73+
};
74+
};
75+
};

csi_http_server/header.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// header.h
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+
#pragma once
11+
#include <string>
12+
namespace csi
13+
{
14+
namespace http
15+
{
16+
struct header_t
17+
{
18+
header_t() {}
19+
header_t(const std::string& n, const std::string& v) : name(n), value(v) {}
20+
std::string name;
21+
std::string value;
22+
};
23+
}; // namespace http
24+
}; // namespace csi
25+

0 commit comments

Comments
 (0)