[WIP] Add asio client interface
This commit is contained in:
parent
838fb33892
commit
26304546c4
|
@ -58,10 +58,17 @@ endif # ENABLE_TINY_NGHTTPD
|
|||
|
||||
if ENABLE_ASIO_LIB
|
||||
|
||||
noinst_PROGRAMS += asio-sv asio-sv2 asio-sv3
|
||||
noinst_PROGRAMS += asio-sv asio-sv2 asio-sv3 asio-cl
|
||||
|
||||
ASIOCPPFLAGS = ${BOOST_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
ASIOLDADD = $(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@
|
||||
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
||||
${BOOST_LDFLAGS} \
|
||||
${BOOST_ASIO_LIB} \
|
||||
${BOOST_THREAD_LIB} \
|
||||
${BOOST_SYSTEM_LIB} \
|
||||
@OPENSSL_LIBS@ \
|
||||
@APPLDFLAGS@
|
||||
|
||||
asio_sv_SOURCES = asio-sv.cc
|
||||
asio_sv_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
|
@ -75,6 +82,10 @@ asio_sv3_SOURCES = asio-sv3.cc
|
|||
asio_sv3_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_sv3_LDADD = ${ASIOLDADD}
|
||||
|
||||
asio_cl_SOURCES = asio-cl.cc
|
||||
asio_cl_CPPFLAGS = ${ASIOCPPFLAGS}
|
||||
asio_cl_LDADD = ${ASIOLDADD}
|
||||
|
||||
endif # ENABLE_ASIO_LIB
|
||||
|
||||
endif # ENABLE_EXAMPLES
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::client;
|
||||
|
||||
void print_header(const http_header &h) {
|
||||
for (auto &kv : h.items()) {
|
||||
std::cerr << kv.first << ": " << kv.second.value << "\n";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
void print_header(const response &res) {
|
||||
std::cerr << "HTTP/2 " << res.status_code() << "\n";
|
||||
print_header(res.header());
|
||||
}
|
||||
|
||||
void print_header(const request &req) {
|
||||
std::cerr << req.method() << " " << req.scheme() << "://" << req.authority()
|
||||
<< req.path() << " "
|
||||
<< "HTTP/2\n";
|
||||
print_header(req.header());
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23);
|
||||
configure_tls_context(tls_ctx);
|
||||
|
||||
tcp::resolver resolver(io_service);
|
||||
auto endpoint_it = resolver.resolve({"localhost", "3000"});
|
||||
|
||||
session sess(io_service, tls_ctx, endpoint_it);
|
||||
sess.on_connect([&sess]() {
|
||||
std::cerr << "connected" << std::endl;
|
||||
boost::system::error_code ec;
|
||||
auto req = sess.submit(ec, "GET", "https://localhost:3000/",
|
||||
"hello world", {{"cookie", {"foobar", true}}});
|
||||
if (ec) {
|
||||
std::cerr << "error: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
req->on_response([&sess, req](response &res) {
|
||||
std::cerr << "response header was received" << std::endl;
|
||||
print_header(res);
|
||||
|
||||
res.on_data([&sess](const uint8_t *data, std::size_t len) {
|
||||
std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
req->on_close([&sess](uint32_t error_code) {
|
||||
std::cerr << "request done with error_code=" << error_code << std::endl;
|
||||
});
|
||||
|
||||
req->on_push([](request &push_req) {
|
||||
std::cerr << "push request was received" << std::endl;
|
||||
|
||||
print_header(push_req);
|
||||
|
||||
push_req.on_response([](response &res) {
|
||||
std::cerr << "push response header was received" << std::endl;
|
||||
|
||||
res.on_data([](const uint8_t *data, std::size_t len) {
|
||||
// std::cerr.write(reinterpret_cast<const char *>(data), len);
|
||||
// std::cerr << std::endl;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
sess.on_error([](const std::string &error) {
|
||||
std::cerr << "error: " << error << std::endl;
|
||||
});
|
||||
|
||||
io_service.run();
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -179,7 +179,18 @@ libnghttp2_asio_la_SOURCES = \
|
|||
asio_http2_handler.cc asio_http2_handler.h \
|
||||
asio_http2_impl.cc asio_http2_impl.h \
|
||||
util.cc util.h http2.cc http2.h \
|
||||
ssl.cc ssl.h
|
||||
ssl.cc ssl.h \
|
||||
asio_common.cc asio_common.h \
|
||||
asio_client_session.cc \
|
||||
asio_client_session_impl.cc asio_client_session_impl.h \
|
||||
asio_client_session_tcp_impl.cc asio_client_session_tcp_impl.h \
|
||||
asio_client_session_tls_impl.cc asio_client_session_tls_impl.h \
|
||||
asio_client_response.cc \
|
||||
asio_client_response_impl.cc asio_client_response_impl.h \
|
||||
asio_client_request.cc \
|
||||
asio_client_request_impl.cc asio_client_request_impl.h \
|
||||
asio_client_stream.cc asio_client_stream.h \
|
||||
asio_client_tls_context.cc asio_client_tls_context.h
|
||||
|
||||
libnghttp2_asio_la_CPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
||||
libnghttp2_asio_la_LDFLAGS = -no-undefined -version-info 0:0:0
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
#include "asio_client_request_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
request::request() : impl_(make_unique<request_impl>()) {}
|
||||
|
||||
request::~request() {}
|
||||
|
||||
void request::cancel() { impl_->cancel(); }
|
||||
|
||||
void request::on_response(response_cb cb) { impl_->on_response(std::move(cb)); }
|
||||
|
||||
void request::on_push(request_cb cb) { impl_->on_push(std::move(cb)); }
|
||||
|
||||
void request::on_close(close_cb cb) { impl_->on_close(std::move(cb)); }
|
||||
|
||||
const std::string &request::method() const { return impl_->method(); }
|
||||
|
||||
const std::string &request::scheme() const { return impl_->scheme(); }
|
||||
|
||||
const std::string &request::path() const { return impl_->path(); }
|
||||
|
||||
const std::string &request::authority() const { return impl_->authority(); }
|
||||
|
||||
const std::string &request::host() const { return impl_->host(); }
|
||||
|
||||
const http_header &request::header() const { return impl_->header(); }
|
||||
|
||||
request_impl &request::impl() { return *impl_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_request_impl.h"
|
||||
|
||||
#include "asio_client_stream.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
request_impl::request_impl() : strm_(nullptr) {}
|
||||
|
||||
void request_impl::cancel() { strm_->cancel(); }
|
||||
|
||||
void request_impl::on_response(response_cb cb) { response_cb_ = std::move(cb); }
|
||||
|
||||
void request_impl::call_on_response(response &res) {
|
||||
if (response_cb_) {
|
||||
response_cb_(res);
|
||||
}
|
||||
}
|
||||
|
||||
void request_impl::on_push(request_cb cb) { push_request_cb_ = std::move(cb); }
|
||||
|
||||
void request_impl::call_on_push(request &push_req) {
|
||||
if (push_request_cb_) {
|
||||
push_request_cb_(push_req);
|
||||
}
|
||||
};
|
||||
|
||||
void request_impl::on_close(close_cb cb) { close_cb_ = std::move(cb); }
|
||||
|
||||
void request_impl::call_on_close(uint32_t error_code) {
|
||||
if (close_cb_) {
|
||||
close_cb_(error_code);
|
||||
}
|
||||
}
|
||||
|
||||
void request_impl::on_read(read_cb cb) { read_cb_ = std::move(cb); }
|
||||
|
||||
read_cb::result_type request_impl::call_on_read(uint8_t *buf, std::size_t len) {
|
||||
if (read_cb_) {
|
||||
return read_cb_(buf, len);
|
||||
}
|
||||
return read_cb::result_type{};
|
||||
}
|
||||
|
||||
void request_impl::header(http_header h) { header_ = std::move(h); }
|
||||
|
||||
http_header &request_impl::header() { return header_; }
|
||||
|
||||
const http_header &request_impl::header() const { return header_; }
|
||||
|
||||
void request_impl::stream(class stream *strm) { strm_ = strm; }
|
||||
|
||||
void request_impl::method(std::string s) { method_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::method() const { return method_; }
|
||||
|
||||
void request_impl::scheme(std::string s) { scheme_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::scheme() const { return scheme_; }
|
||||
|
||||
void request_impl::path(std::string s) { path_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::path() const { return path_; }
|
||||
|
||||
void request_impl::authority(std::string s) { authority_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::authority() const { return authority_; }
|
||||
|
||||
void request_impl::host(std::string s) { host_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::host() const { return host_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_REQUEST_IMPL_H
|
||||
#define ASIO_CLIENT_REQUEST_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class response;
|
||||
class stream;
|
||||
|
||||
class request_impl {
|
||||
public:
|
||||
request_impl();
|
||||
|
||||
request_impl(const request_impl &) = delete;
|
||||
request_impl &operator=(const request_impl &) = delete;
|
||||
|
||||
void cancel();
|
||||
|
||||
void on_response(response_cb cb);
|
||||
void call_on_response(response &res);
|
||||
|
||||
void on_push(request_cb cb);
|
||||
void call_on_push(request &push_req);
|
||||
|
||||
void on_close(close_cb cb);
|
||||
void call_on_close(uint32_t error_code);
|
||||
|
||||
void on_read(read_cb cb);
|
||||
read_cb::result_type call_on_read(uint8_t *buf, std::size_t len);
|
||||
|
||||
void header(http_header h);
|
||||
http_header &header();
|
||||
const http_header &header() const;
|
||||
|
||||
void stream(class stream *strm);
|
||||
|
||||
void method(std::string s);
|
||||
const std::string &method() const;
|
||||
|
||||
void scheme(std::string s);
|
||||
const std::string &scheme() const;
|
||||
|
||||
void path(std::string s);
|
||||
const std::string &path() const;
|
||||
|
||||
void authority(std::string s);
|
||||
const std::string &authority() const;
|
||||
|
||||
void host(std::string s);
|
||||
const std::string &host() const;
|
||||
|
||||
private:
|
||||
http_header header_;
|
||||
response_cb response_cb_;
|
||||
request_cb push_request_cb_;
|
||||
close_cb close_cb_;
|
||||
read_cb read_cb_;
|
||||
class stream *strm_;
|
||||
std::string method_;
|
||||
std::string scheme_;
|
||||
std::string path_;
|
||||
std::string authority_;
|
||||
std::string host_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_REQUEST_IMPL_H
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
#include "asio_client_response_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
response::response() : impl_(make_unique<response_impl>()) {}
|
||||
|
||||
response::~response() {}
|
||||
|
||||
void response::on_data(data_cb cb) { impl_->on_data(std::move(cb)); }
|
||||
|
||||
int response::status_code() const { return impl_->status_code(); }
|
||||
|
||||
int64_t response::content_length() const { return impl_->content_length(); }
|
||||
|
||||
const http_header &response::header() const { return impl_->header(); }
|
||||
|
||||
response_impl &response::impl() { return *impl_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_response_impl.h"
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
response_impl::response_impl() : content_length_(-1), status_code_(0) {}
|
||||
|
||||
void response_impl::on_data(data_cb cb) { data_cb_ = std::move(cb); }
|
||||
|
||||
void response_impl::call_on_data(const uint8_t *data, std::size_t len) {
|
||||
if (data_cb_) {
|
||||
data_cb_(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
void response_impl::status_code(int sc) { status_code_ = sc; }
|
||||
|
||||
int response_impl::status_code() const { return status_code_; }
|
||||
|
||||
void response_impl::content_length(int64_t n) { content_length_ = n; }
|
||||
|
||||
int64_t response_impl::content_length() const { return content_length_; }
|
||||
|
||||
http_header &response_impl::header() { return header_; }
|
||||
|
||||
const http_header &response_impl::header() const { return header_; }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_RESPONSE_IMPL_H
|
||||
#define ASIO_CLIENT_RESPONSE_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class response_impl {
|
||||
public:
|
||||
response_impl();
|
||||
|
||||
response_impl(const response_impl &) = delete;
|
||||
response_impl &operator=(const response_impl &) = delete;
|
||||
|
||||
void on_data(data_cb cb);
|
||||
|
||||
void call_on_data(const uint8_t *data, std::size_t len);
|
||||
|
||||
void status_code(int sc);
|
||||
int status_code() const;
|
||||
|
||||
void content_length(int64_t n);
|
||||
int64_t content_length() const;
|
||||
|
||||
http_header &header();
|
||||
const http_header &header() const;
|
||||
|
||||
private:
|
||||
data_cb data_cb_;
|
||||
|
||||
http_header header_;
|
||||
|
||||
int64_t content_length_;
|
||||
int status_code_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_RESPONSE_IMPL_H
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
#include "asio_client_session_tcp_impl.h"
|
||||
#include "asio_client_session_tls_impl.h"
|
||||
#include "asio_common.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
session::session(boost::asio::io_service &io_service,
|
||||
tcp::resolver::iterator endpoint_it)
|
||||
: impl_(make_unique<session_tcp_impl>(io_service, endpoint_it)) {}
|
||||
|
||||
session::session(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_ctx,
|
||||
tcp::resolver::iterator endpoint_it)
|
||||
: impl_(make_unique<session_tls_impl>(io_service, tls_ctx, endpoint_it)) {}
|
||||
|
||||
session::~session() {}
|
||||
|
||||
void session::on_connect(void_cb cb) { impl_->on_connect(std::move(cb)); }
|
||||
|
||||
void session::on_error(error_cb cb) { impl_->on_error(std::move(cb)); }
|
||||
|
||||
void session::shutdown() { impl_->shutdown(); }
|
||||
|
||||
request *session::submit(boost::system::error_code &ec,
|
||||
const std::string &method, const std::string &uri,
|
||||
http_header h) {
|
||||
return impl_->submit(ec, method, uri, read_cb(), std::move(h));
|
||||
}
|
||||
|
||||
request *session::submit(boost::system::error_code &ec,
|
||||
const std::string &method, const std::string &uri,
|
||||
std::string data, http_header h) {
|
||||
return impl_->submit(ec, method, uri, string_reader(std::move(data)),
|
||||
std::move(h));
|
||||
}
|
||||
|
||||
request *session::submit(boost::system::error_code &ec,
|
||||
const std::string &method, const std::string &uri,
|
||||
read_cb cb, http_header h) {
|
||||
return impl_->submit(ec, method, uri, std::move(cb), std::move(h));
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // nghttp2
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "asio_client_stream.h"
|
||||
#include "asio_client_request_impl.h"
|
||||
#include "asio_client_response_impl.h"
|
||||
#include "asio_common.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
#include "http2.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
session_impl::session_impl()
|
||||
: wblen_(0), session_(nullptr), data_pending_(nullptr), data_pendinglen_(0),
|
||||
writing_(false), inside_callback_(false) {}
|
||||
|
||||
session_impl::~session_impl() {
|
||||
// finish up all active stream with CANCEL error code
|
||||
for (auto &p : streams_) {
|
||||
auto &strm = p.second;
|
||||
auto &req = strm->request().impl();
|
||||
req.call_on_close(NGHTTP2_CANCEL);
|
||||
}
|
||||
|
||||
nghttp2_session_del(session_);
|
||||
}
|
||||
|
||||
void session_impl::connected() {
|
||||
if (!setup_session()) {
|
||||
return;
|
||||
}
|
||||
|
||||
socket().set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
|
||||
std::copy_n(NGHTTP2_CLIENT_CONNECTION_PREFACE,
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN, std::begin(wb_));
|
||||
wblen_ = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
|
||||
|
||||
do_write();
|
||||
do_read();
|
||||
|
||||
auto &connect_cb = on_connect();
|
||||
if (connect_cb) {
|
||||
connect_cb();
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::not_connected(const boost::system::error_code &ec) {
|
||||
auto &error_cb = on_error();
|
||||
if (error_cb) {
|
||||
error_cb(ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::on_connect(void_cb cb) { connect_cb_ = std::move(cb); }
|
||||
|
||||
void session_impl::on_error(error_cb cb) { error_cb_ = std::move(cb); }
|
||||
|
||||
const void_cb &session_impl::on_connect() const { return connect_cb_; }
|
||||
|
||||
const error_cb &session_impl::on_error() const { return error_cb_; }
|
||||
|
||||
namespace {
|
||||
int on_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data) {
|
||||
if (frame->hd.type != NGHTTP2_PUSH_PROMISE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
sess->create_push_stream(frame->push_promise.promised_stream_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, uint8_t flags,
|
||||
void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
stream *strm;
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS: {
|
||||
strm = sess->find_stream(frame->hd.stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ignore trailers
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
|
||||
!strm->expect_final_response()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
auto &res = strm->response().impl();
|
||||
if (token == http2::HD__STATUS) {
|
||||
res.status_code(util::parse_uint(value, valuelen));
|
||||
} else {
|
||||
|
||||
if (token == http2::HD_CONTENT_LENGTH) {
|
||||
res.content_length(util::parse_uint(value, valuelen));
|
||||
}
|
||||
|
||||
res.header().add(std::string(name, name + namelen),
|
||||
std::string(value, value + valuelen),
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_PUSH_PROMISE: {
|
||||
strm = sess->find_stream(frame->push_promise.promised_stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
|
||||
switch (http2::lookup_token(name, namelen)) {
|
||||
case http2::HD__METHOD:
|
||||
req.method(std::string(value, value + valuelen));
|
||||
break;
|
||||
case http2::HD__SCHEME:
|
||||
req.scheme(std::string(value, value + valuelen));
|
||||
break;
|
||||
case http2::HD__PATH:
|
||||
req.path(std::string(value, value + valuelen));
|
||||
break;
|
||||
case http2::HD__AUTHORITY:
|
||||
req.authority(std::string(value, value + valuelen));
|
||||
// host defaults to authority value
|
||||
req.host(std::string(value, value + valuelen));
|
||||
break;
|
||||
case http2::HD_HOST:
|
||||
req.host(std::string(value, value + valuelen));
|
||||
// fall through
|
||||
default:
|
||||
req.header().add(std::string(name, name + namelen),
|
||||
std::string(value, value + valuelen),
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
auto strm = sess->find_stream(frame->hd.stream_id);
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA: {
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
strm->response().impl().call_on_data(nullptr, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_HEADERS: {
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ignore trailers
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
|
||||
!strm->expect_final_response()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strm->expect_final_response()) {
|
||||
// wait for final response
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
req.call_on_response(strm->response());
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
strm->response().impl().call_on_data(nullptr, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_PUSH_PROMISE: {
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto push_strm = sess->find_stream(frame->push_promise.promised_stream_id);
|
||||
if (!push_strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strm->request().impl().call_on_push(push_strm->request());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
auto strm = sess->find_stream(stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto &res = strm->response().impl();
|
||||
res.call_on_data(data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *user_data) {
|
||||
auto sess = static_cast<session_impl *>(user_data);
|
||||
auto strm = sess->pop_stream(stream_id);
|
||||
if (!strm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strm->request().impl().call_on_close(error_code);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool session_impl::setup_session() {
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
defer(nghttp2_session_callbacks_del, callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
auto rv = nghttp2_session_client_new(&session_, callbacks, this);
|
||||
if (rv != 0) {
|
||||
auto &error_cb = on_error();
|
||||
if (error_cb) {
|
||||
error_cb(nghttp2_strerror(rv));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nghttp2_settings_entry iv = {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100};
|
||||
nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, &iv, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void session_impl::cancel(stream &strm) {
|
||||
nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE, strm.stream_id(),
|
||||
NGHTTP2_CANCEL);
|
||||
}
|
||||
|
||||
stream *session_impl::find_stream(int32_t stream_id) {
|
||||
auto it = streams_.find(stream_id);
|
||||
if (it == std::end(streams_)) {
|
||||
return nullptr;
|
||||
}
|
||||
return (*it).second.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<stream> session_impl::pop_stream(int32_t stream_id) {
|
||||
auto it = streams_.find(stream_id);
|
||||
if (it == std::end(streams_)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto strm = std::move((*it).second);
|
||||
streams_.erase(it);
|
||||
return strm;
|
||||
}
|
||||
|
||||
stream *session_impl::create_push_stream(int32_t stream_id) {
|
||||
auto strm = create_stream();
|
||||
strm->stream_id(stream_id);
|
||||
auto p = streams_.emplace(stream_id, std::move(strm));
|
||||
assert(p.second);
|
||||
return (*p.first).second.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<stream> session_impl::create_stream() {
|
||||
auto strm = make_unique<stream>(this);
|
||||
|
||||
auto &req = strm->request().impl();
|
||||
req.stream(strm.get());
|
||||
|
||||
return strm;
|
||||
}
|
||||
|
||||
request *session_impl::submit(boost::system::error_code &ec,
|
||||
const std::string &method, const std::string &uri,
|
||||
read_cb cb, http_header h) {
|
||||
ec.clear();
|
||||
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(3 + h.size());
|
||||
nva.push_back(http2::make_nv_ls(":method", method));
|
||||
nva.push_back(http2::make_nv_ll(":scheme", "https"));
|
||||
nva.push_back(http2::make_nv_ll(":path", "/"));
|
||||
nva.push_back(http2::make_nv_ll(":authority", "localhost:3000"));
|
||||
for (auto &kv : h.items()) {
|
||||
nva.push_back(
|
||||
http2::make_nv(kv.first, kv.second.value, kv.second.sensitive));
|
||||
}
|
||||
|
||||
auto strm = create_stream();
|
||||
auto &req = strm->request().impl();
|
||||
req.header(std::move(h));
|
||||
|
||||
nghttp2_data_provider *prdptr = nullptr;
|
||||
nghttp2_data_provider prd;
|
||||
|
||||
if (cb) {
|
||||
strm->request().impl().on_read(std::move(cb));
|
||||
prd.source.ptr = strm.get();
|
||||
prd.read_callback =
|
||||
[](nghttp2_session *session, int32_t stream_id, uint8_t *buf,
|
||||
size_t length, uint32_t *data_flags, nghttp2_data_source *source,
|
||||
void *user_data) -> ssize_t {
|
||||
auto strm = static_cast<stream *>(source->ptr);
|
||||
auto rv = strm->request().impl().call_on_read(buf, length);
|
||||
if (rv.first < 0) {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if (rv.second) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
} else if (rv.first == 0) {
|
||||
return NGHTTP2_ERR_DEFERRED;
|
||||
}
|
||||
|
||||
return rv.first;
|
||||
};
|
||||
prdptr = &prd;
|
||||
}
|
||||
|
||||
auto stream_id = nghttp2_submit_request(session_, nullptr, nva.data(),
|
||||
nva.size(), prdptr, strm.get());
|
||||
if (stream_id < 0) {
|
||||
ec = make_error_code(static_cast<nghttp2_error>(stream_id));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
signal_write();
|
||||
|
||||
strm->stream_id(stream_id);
|
||||
|
||||
auto p = streams_.emplace(stream_id, std::move(strm));
|
||||
assert(p.second);
|
||||
return &(*p.first).second->request();
|
||||
}
|
||||
|
||||
void session_impl::shutdown() {
|
||||
nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR);
|
||||
signal_write();
|
||||
}
|
||||
|
||||
void session_impl::signal_write() {
|
||||
if (!inside_callback_) {
|
||||
do_write();
|
||||
}
|
||||
}
|
||||
|
||||
bool session_impl::should_stop() const {
|
||||
return !writing_ && !nghttp2_session_want_read(session_) &&
|
||||
!nghttp2_session_want_write(session_);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct callback_guard {
|
||||
callback_guard(session_impl &sess) : sess(sess) { sess.enter_callback(); }
|
||||
~callback_guard() { sess.leave_callback(); }
|
||||
|
||||
session_impl &sess;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void session_impl::enter_callback() {
|
||||
assert(!inside_callback_);
|
||||
inside_callback_ = true;
|
||||
}
|
||||
|
||||
void session_impl::leave_callback() {
|
||||
assert(inside_callback_);
|
||||
inside_callback_ = false;
|
||||
}
|
||||
|
||||
void session_impl::do_read() {
|
||||
read_socket([this](const boost::system::error_code &ec,
|
||||
std::size_t bytes_transferred) {
|
||||
if (ec) {
|
||||
if (ec.value() == boost::asio::error::operation_aborted) {
|
||||
shutdown_socket();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
callback_guard cg(*this);
|
||||
|
||||
auto rv =
|
||||
nghttp2_session_mem_recv(session_, rb_.data(), bytes_transferred);
|
||||
|
||||
if (rv != static_cast<ssize_t>(bytes_transferred)) {
|
||||
shutdown_socket();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do_write();
|
||||
|
||||
if (should_stop()) {
|
||||
shutdown_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
do_read();
|
||||
});
|
||||
}
|
||||
|
||||
void session_impl::do_write() {
|
||||
if (writing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_pending_) {
|
||||
std::copy_n(data_pending_, data_pendinglen_, std::begin(wb_) + wblen_);
|
||||
|
||||
wblen_ += data_pendinglen_;
|
||||
|
||||
data_pending_ = nullptr;
|
||||
data_pendinglen_ = 0;
|
||||
}
|
||||
|
||||
{
|
||||
callback_guard cg(*this);
|
||||
|
||||
for (;;) {
|
||||
const uint8_t *data;
|
||||
auto n = nghttp2_session_mem_send(session_, &data);
|
||||
if (n < 0) {
|
||||
shutdown_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (wblen_ + n > wb_.size()) {
|
||||
data_pending_ = data;
|
||||
data_pendinglen_ = n;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
std::copy_n(data, n, std::begin(wb_) + wblen_);
|
||||
|
||||
wblen_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
if (wblen_ == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
writing_ = true;
|
||||
|
||||
write_socket([this](const boost::system::error_code &ec, std::size_t n) {
|
||||
if (ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
wblen_ = 0;
|
||||
writing_ = false;
|
||||
|
||||
do_write();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // nghttp2
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_SESSION_IMPL_H
|
||||
#define ASIO_CLIENT_SESSION_IMPL_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class stream;
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class session_impl {
|
||||
public:
|
||||
session_impl();
|
||||
virtual ~session_impl();
|
||||
|
||||
void connected();
|
||||
void not_connected(const boost::system::error_code &ec);
|
||||
|
||||
void on_connect(void_cb cb);
|
||||
void on_error(error_cb cb);
|
||||
|
||||
const void_cb &on_connect() const;
|
||||
const error_cb &on_error() const;
|
||||
|
||||
void cancel(stream &strm);
|
||||
|
||||
std::unique_ptr<stream> create_stream();
|
||||
std::unique_ptr<stream> pop_stream(int32_t stream_id);
|
||||
stream *create_push_stream(int32_t stream_id);
|
||||
stream *find_stream(int32_t stream_id);
|
||||
|
||||
request *submit(boost::system::error_code &ec, const std::string &method,
|
||||
const std::string &uri, read_cb cb, http_header h);
|
||||
|
||||
virtual tcp::socket &socket() = 0;
|
||||
virtual void read_socket(std::function<
|
||||
void(const boost::system::error_code &ec, std::size_t n)> h) = 0;
|
||||
virtual void write_socket(std::function<
|
||||
void(const boost::system::error_code &ec, std::size_t n)> h) = 0;
|
||||
virtual void shutdown_socket() = 0;
|
||||
|
||||
void shutdown();
|
||||
|
||||
void signal_write();
|
||||
|
||||
void enter_callback();
|
||||
void leave_callback();
|
||||
|
||||
void do_read();
|
||||
void do_write();
|
||||
|
||||
protected:
|
||||
boost::array<uint8_t, 8192> rb_;
|
||||
boost::array<uint8_t, 65536> wb_;
|
||||
std::size_t wblen_;
|
||||
|
||||
private:
|
||||
bool should_stop() const;
|
||||
bool setup_session();
|
||||
|
||||
std::map<int32_t, std::unique_ptr<stream>> streams_;
|
||||
|
||||
void_cb connect_cb_;
|
||||
error_cb error_cb_;
|
||||
|
||||
nghttp2_session *session_;
|
||||
|
||||
const uint8_t *data_pending_;
|
||||
std::size_t data_pendinglen_;
|
||||
|
||||
bool writing_;
|
||||
bool inside_callback_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_SESSION_IMPL_H
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_session_tcp_impl.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
session_tcp_impl::session_tcp_impl(boost::asio::io_service &io_service,
|
||||
tcp::resolver::iterator endpoint_it)
|
||||
: socket_(io_service) {
|
||||
|
||||
boost::asio::async_connect(socket_, endpoint_it,
|
||||
[this](boost::system::error_code ec,
|
||||
tcp::resolver::iterator endpoint_it) {
|
||||
if (!ec) {
|
||||
connected();
|
||||
return;
|
||||
}
|
||||
not_connected(ec);
|
||||
});
|
||||
}
|
||||
|
||||
session_tcp_impl::~session_tcp_impl() {}
|
||||
|
||||
tcp::socket &session_tcp_impl::socket() { return socket_; }
|
||||
|
||||
void session_tcp_impl::read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
socket_.async_read_some(boost::asio::buffer(rb_), h);
|
||||
}
|
||||
|
||||
void session_tcp_impl::write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(wb_, wblen_), h);
|
||||
}
|
||||
|
||||
void session_tcp_impl::shutdown_socket() { socket_.close(); }
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_SESSION_TCP_IMPL_H
|
||||
#define ASIO_CLIENT_SESSION_TCP_IMPL_H
|
||||
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class session_tcp_impl : public session_impl {
|
||||
public:
|
||||
session_tcp_impl(boost::asio::io_service &io_service,
|
||||
tcp::resolver::iterator endpoint_it);
|
||||
virtual ~session_tcp_impl();
|
||||
|
||||
virtual tcp::socket &socket();
|
||||
virtual void read_socket(std::function<
|
||||
void(const boost::system::error_code &ec, std::size_t n)> h);
|
||||
virtual void write_socket(std::function<
|
||||
void(const boost::system::error_code &ec, std::size_t n)> h);
|
||||
virtual void shutdown_socket();
|
||||
|
||||
private:
|
||||
tcp::socket socket_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_SESSION_TCP_IMPL_H
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_session_tls_impl.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
session_tls_impl::session_tls_impl(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_ctx,
|
||||
tcp::resolver::iterator endpoint_it)
|
||||
: socket_(io_service, tls_ctx) {
|
||||
|
||||
boost::asio::async_connect(socket(), endpoint_it,
|
||||
[this](boost::system::error_code ec,
|
||||
tcp::resolver::iterator endpoint_it) {
|
||||
if (ec) {
|
||||
not_connected(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
socket_.async_handshake(boost::asio::ssl::stream_base::client,
|
||||
[this](const boost::system::error_code &ec) {
|
||||
if (ec) {
|
||||
not_connected(ec);
|
||||
return;
|
||||
}
|
||||
connected();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
session_tls_impl::~session_tls_impl() {}
|
||||
|
||||
tcp::socket &session_tls_impl::socket() { return socket_.next_layer(); }
|
||||
|
||||
void session_tls_impl::read_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
socket_.async_read_some(boost::asio::buffer(rb_), h);
|
||||
}
|
||||
|
||||
void session_tls_impl::write_socket(
|
||||
std::function<void(const boost::system::error_code &ec, std::size_t n)> h) {
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(wb_, wblen_), h);
|
||||
}
|
||||
|
||||
void session_tls_impl::shutdown_socket() {
|
||||
socket_.async_shutdown([](const boost::system::error_code &ec) {});
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_SESSION_TLS_IMPL_H
|
||||
#define ASIO_CLIENT_SESSION_TLS_IMPL_H
|
||||
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
|
||||
|
||||
class session_tls_impl : public session_impl {
|
||||
public:
|
||||
session_tls_impl(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_ctx,
|
||||
tcp::resolver::iterator endpoint_it);
|
||||
virtual ~session_tls_impl();
|
||||
|
||||
virtual tcp::socket &socket();
|
||||
virtual void read_socket(std::function<
|
||||
void(const boost::system::error_code &ec, std::size_t n)> h);
|
||||
virtual void write_socket(std::function<
|
||||
void(const boost::system::error_code &ec, std::size_t n)> h);
|
||||
virtual void shutdown_socket();
|
||||
|
||||
private:
|
||||
ssl_socket socket_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_SESSION_TLS_IMPL_H
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_stream.h"
|
||||
|
||||
#include "asio_client_request_impl.h"
|
||||
#include "asio_client_response_impl.h"
|
||||
#include "asio_client_session_impl.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
stream::stream(session_impl *sess) : sess_(sess), stream_id_(0) {}
|
||||
|
||||
void stream::cancel() { sess_->cancel(*this); }
|
||||
|
||||
void stream::stream_id(int32_t stream_id) { stream_id_ = stream_id; }
|
||||
|
||||
int32_t stream::stream_id() const { return stream_id_; }
|
||||
|
||||
request &stream::request() { return request_; }
|
||||
|
||||
response &stream::response() { return response_; }
|
||||
|
||||
bool stream::expect_final_response() const {
|
||||
return response_.status_code() / 100 == 1;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_STREAM_H
|
||||
#define ASIO_CLIENT_STREAM_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
class request;
|
||||
class response;
|
||||
class session_impl;
|
||||
|
||||
class stream {
|
||||
public:
|
||||
stream(session_impl *sess);
|
||||
|
||||
stream(const stream &) = delete;
|
||||
stream &operator=(const stream &) = delete;
|
||||
|
||||
void cancel();
|
||||
|
||||
void stream_id(int32_t stream_id);
|
||||
int32_t stream_id() const;
|
||||
|
||||
request &request();
|
||||
response &response();
|
||||
|
||||
bool expect_final_response() const;
|
||||
|
||||
private:
|
||||
nghttp2::asio_http2::client::request request_;
|
||||
nghttp2::asio_http2::client::response response_;
|
||||
session_impl *sess_;
|
||||
uint32_t stream_id_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_CLIENT_STREAM_H
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_client_tls_context.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include "ssl.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen)) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void configure_tls_context(boost::asio::ssl::context &tls_ctx) {
|
||||
auto ctx = tls_ctx.native_handle();
|
||||
|
||||
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
|
||||
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
||||
|
||||
SSL_CTX_set_next_proto_select_cb(ctx, client_select_next_proto_cb, nullptr);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_CLIENT_TLS_CONTEXT_H
|
||||
#define ASIO_CLIENT_TLS_CONTEXT_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
#endif // ASIO_CLIENT_TLS_CONTEXT_H
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "asio_common.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
|
||||
class nghttp2_category_impl : public boost::system::error_category {
|
||||
public:
|
||||
const char *name() const noexcept { return "nghttp2"; }
|
||||
std::string message(int ev) const { return nghttp2_strerror(ev); }
|
||||
};
|
||||
|
||||
const boost::system::error_category &nghttp2_category() noexcept {
|
||||
static nghttp2_category_impl cat;
|
||||
return cat;
|
||||
}
|
||||
|
||||
boost::system::error_code make_error_code(nghttp2_error ev) {
|
||||
return boost::system::error_code(static_cast<int>(ev), nghttp2_category());
|
||||
}
|
||||
|
||||
read_cb string_reader(std::string data) {
|
||||
auto strio = std::make_shared<std::pair<std::string, size_t>>(std::move(data),
|
||||
data.size());
|
||||
return [strio](uint8_t *buf, size_t len) {
|
||||
auto n = std::min(len, strio->second);
|
||||
std::copy_n(strio->first.c_str(), n, buf);
|
||||
strio->second -= n;
|
||||
return std::make_pair(n, strio->second == 0);
|
||||
};
|
||||
}
|
||||
|
||||
http_header::http_header() {}
|
||||
|
||||
http_header::http_header(
|
||||
std::initializer_list<std::pair<std::string, header_value>> ilist) {
|
||||
for (auto &kv : ilist) {
|
||||
auto name = kv.first;
|
||||
util::inp_strlower(name);
|
||||
items_.emplace(std::move(name), kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
http_header &http_header::
|
||||
operator=(std::initializer_list<std::pair<std::string, header_value>> ilist) {
|
||||
items_.clear();
|
||||
for (auto &kv : ilist) {
|
||||
auto name = kv.first;
|
||||
util::inp_strlower(name);
|
||||
items_.emplace(std::move(name), kv.second);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const header_map &http_header::items() const { return items_; }
|
||||
|
||||
void http_header::add(std::string name, std::string value, bool sensitive) {
|
||||
util::inp_strlower(name);
|
||||
items_.emplace(name, header_value(value, sensitive));
|
||||
}
|
||||
|
||||
const header_value *http_header::get(const std::string &name) const {
|
||||
auto it = items_.find(name);
|
||||
if (it == std::end(items_)) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(*it).second;
|
||||
}
|
||||
|
||||
std::size_t http_header::size() const { return items_.size(); }
|
||||
|
||||
bool http_header::empty() const { return items_.empty(); }
|
||||
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ASIO_COMMON_H
|
||||
#define ASIO_COMMON_H
|
||||
|
||||
#include "nghttp2_config.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <nghttp2/asio_http2.h>
|
||||
|
||||
namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
|
||||
read_cb string_reader(std::string data);
|
||||
|
||||
boost::system::error_code make_error_code(nghttp2_error ev);
|
||||
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // ASIO_COMMON_H
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "asio_common.h"
|
||||
#include "http2.h"
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
|
@ -206,20 +207,7 @@ void response_impl::end(std::string data) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto strio = std::make_shared<std::pair<std::string, size_t>>(std::move(data),
|
||||
data.size());
|
||||
auto read_cb = [strio](uint8_t *buf, size_t len) {
|
||||
auto nread = std::min(len, strio->second);
|
||||
memcpy(buf, strio->first.c_str(), nread);
|
||||
strio->second -= nread;
|
||||
if (strio->second == 0) {
|
||||
return std::make_pair(nread, true);
|
||||
}
|
||||
|
||||
return std::make_pair(nread, false);
|
||||
};
|
||||
|
||||
end(std::move(read_cb));
|
||||
end(string_reader(std::move(data)));
|
||||
}
|
||||
|
||||
void response_impl::end(read_cb cb) {
|
||||
|
|
|
@ -92,7 +92,6 @@ void http2_impl::listen(const std::string &address, uint16_t port,
|
|||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
|
||||
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
||||
|
||||
|
|
|
@ -30,18 +30,79 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
namespace boost {
|
||||
namespace system {
|
||||
|
||||
template <> struct is_error_code_enum<nghttp2_error> {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace asio_http2 {
|
||||
|
||||
struct header {
|
||||
header() : sensitive(false) {}
|
||||
header(std::string name, std::string value, bool sensitive = false)
|
||||
: name(std::move(name)), value(std::move(value)), sensitive(sensitive) {}
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
bool sensitive;
|
||||
};
|
||||
|
||||
struct header_value {
|
||||
header_value(std::string value, bool sensitive = false)
|
||||
: value(std::move(value)), sensitive(sensitive) {}
|
||||
|
||||
std::string value;
|
||||
bool sensitive;
|
||||
};
|
||||
|
||||
using header_map = std::multimap<std::string, header_value>;
|
||||
|
||||
class http_header {
|
||||
public:
|
||||
http_header();
|
||||
http_header(const http_header &other) = default;
|
||||
http_header(http_header &&other) = default;
|
||||
http_header(
|
||||
std::initializer_list<std::pair<std::string, header_value>> ilist);
|
||||
|
||||
http_header &operator=(const http_header &other) = default;
|
||||
http_header &operator=(http_header &&other) = default;
|
||||
http_header &
|
||||
operator=(std::initializer_list<std::pair<std::string, header_value>> ilist);
|
||||
|
||||
const header_map &items() const;
|
||||
|
||||
void add(std::string name, std::string value, bool sensitive);
|
||||
const header_value *get(const std::string &name) const;
|
||||
|
||||
std::size_t size() const;
|
||||
bool empty() const;
|
||||
|
||||
private:
|
||||
header_map items_;
|
||||
};
|
||||
|
||||
const boost::system::error_category &nghttp2_category() noexcept;
|
||||
|
||||
typedef std::function<void(const uint8_t *, std::size_t)> data_cb;
|
||||
typedef std::function<void(void)> void_cb;
|
||||
typedef std::function<void(const std::string &err)> error_cb;
|
||||
typedef std::function<void(uint32_t)> close_cb;
|
||||
|
||||
// Callback function to generate response body. The implementation of
|
||||
// this callback must fill at most |len| bytes data to |buf|. The
|
||||
|
@ -103,9 +164,9 @@ public:
|
|||
// string. In this case, check host().
|
||||
|
||||
const std::string &authority() const;
|
||||
|
||||
// Returns host (e.g., example.org). If host header field is not
|
||||
// present, this value is copied from authority().
|
||||
|
||||
const std::string &host() const;
|
||||
|
||||
// Returns path (e.g., /index.html).
|
||||
|
@ -242,6 +303,92 @@ std::string percent_decode(const std::string &s);
|
|||
// Returns HTTP date representation of current posix time |t|.
|
||||
std::string http_date(int64_t t);
|
||||
|
||||
namespace client {
|
||||
|
||||
class response_impl;
|
||||
|
||||
class response {
|
||||
public:
|
||||
response();
|
||||
~response();
|
||||
|
||||
void on_data(data_cb cb);
|
||||
|
||||
int status_code() const;
|
||||
|
||||
int64_t content_length() const;
|
||||
|
||||
const http_header &header() const;
|
||||
|
||||
response_impl &impl();
|
||||
|
||||
private:
|
||||
std::unique_ptr<response_impl> impl_;
|
||||
};
|
||||
|
||||
class request;
|
||||
|
||||
using response_cb = std::function<void(response &)>;
|
||||
using request_cb = std::function<void(request &)>;
|
||||
|
||||
class request_impl;
|
||||
|
||||
class request {
|
||||
public:
|
||||
request();
|
||||
~request();
|
||||
|
||||
void on_response(response_cb cb);
|
||||
void on_push(request_cb cb);
|
||||
void on_close(close_cb cb);
|
||||
|
||||
void cancel();
|
||||
|
||||
const std::string &method() const;
|
||||
const std::string &scheme() const;
|
||||
const std::string &path() const;
|
||||
const std::string &authority() const;
|
||||
const std::string &host() const;
|
||||
|
||||
const http_header &header() const;
|
||||
|
||||
request_impl &impl();
|
||||
|
||||
private:
|
||||
std::unique_ptr<request_impl> impl_;
|
||||
};
|
||||
|
||||
class session_impl;
|
||||
|
||||
class session {
|
||||
public:
|
||||
session(boost::asio::io_service &io_service,
|
||||
boost::asio::ip::tcp::resolver::iterator endpoint_it);
|
||||
session(boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &tls_context,
|
||||
boost::asio::ip::tcp::resolver::iterator endpoint_it);
|
||||
~session();
|
||||
|
||||
void on_connect(void_cb cb);
|
||||
void on_error(error_cb cb);
|
||||
|
||||
void shutdown();
|
||||
|
||||
request *submit(boost::system::error_code &ec, const std::string &method,
|
||||
const std::string &uri, http_header h = {});
|
||||
request *submit(boost::system::error_code &ec, const std::string &method,
|
||||
const std::string &uri, std::string data, http_header h = {});
|
||||
request *submit(boost::system::error_code &ec, const std::string &method,
|
||||
const std::string &uri, read_cb cb, http_header h = {});
|
||||
|
||||
private:
|
||||
std::unique_ptr<session_impl> impl_;
|
||||
};
|
||||
|
||||
void configure_tls_context(boost::asio::ssl::context &tls_ctx);
|
||||
|
||||
} // namespace client
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
|
Loading…
Reference in New Issue