2012-11-18 07:23:13 -05:00
|
|
|
/*
|
|
|
|
* Spdylay - SPDY Library
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012 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 "shrpx_spdy_downstream_connection.h"
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <openssl/err.h>
|
|
|
|
|
|
|
|
#include <event2/bufferevent_ssl.h>
|
|
|
|
|
2013-01-05 09:21:09 -05:00
|
|
|
#include "http-parser/http_parser.h"
|
2012-11-20 11:29:39 -05:00
|
|
|
|
2012-11-18 07:23:13 -05:00
|
|
|
#include "shrpx_client_handler.h"
|
|
|
|
#include "shrpx_upstream.h"
|
|
|
|
#include "shrpx_downstream.h"
|
|
|
|
#include "shrpx_config.h"
|
|
|
|
#include "shrpx_error.h"
|
|
|
|
#include "shrpx_http.h"
|
2012-11-20 11:29:39 -05:00
|
|
|
#include "shrpx_spdy_session.h"
|
2012-11-18 07:23:13 -05:00
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
using namespace spdylay;
|
|
|
|
|
|
|
|
namespace shrpx {
|
|
|
|
|
|
|
|
SpdyDownstreamConnection::SpdyDownstreamConnection
|
|
|
|
(ClientHandler *client_handler)
|
|
|
|
: DownstreamConnection(client_handler),
|
2012-11-20 11:29:39 -05:00
|
|
|
spdy_(client_handler->get_spdy_session()),
|
|
|
|
request_body_buf_(0),
|
2012-11-21 09:47:48 -05:00
|
|
|
sd_(0),
|
|
|
|
recv_window_size_(0)
|
2012-11-18 07:23:13 -05:00
|
|
|
{}
|
|
|
|
|
|
|
|
SpdyDownstreamConnection::~SpdyDownstreamConnection()
|
|
|
|
{
|
|
|
|
if(request_body_buf_) {
|
|
|
|
evbuffer_free(request_body_buf_);
|
|
|
|
}
|
2012-11-20 11:29:39 -05:00
|
|
|
// TODO need RST_STREAM?
|
|
|
|
spdy_->remove_downstream_connection(this);
|
|
|
|
// Downstream and DownstreamConnection may be deleted
|
|
|
|
// asynchronously.
|
|
|
|
if(downstream_) {
|
|
|
|
downstream_->set_downstream_connection(0);
|
|
|
|
}
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int SpdyDownstreamConnection::init_request_body_buf()
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
if(request_body_buf_) {
|
|
|
|
rv = evbuffer_drain(request_body_buf_,
|
|
|
|
evbuffer_get_length(request_body_buf_));
|
|
|
|
if(rv != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
request_body_buf_ = evbuffer_new();
|
|
|
|
if(request_body_buf_ == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2012-11-18 12:11:46 -05:00
|
|
|
evbuffer_setcb(request_body_buf_, 0, this);
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SpdyDownstreamConnection::attach_downstream(Downstream *downstream)
|
|
|
|
{
|
|
|
|
if(ENABLE_LOG) {
|
2012-12-09 05:15:14 -05:00
|
|
|
DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
if(init_request_body_buf() == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
2012-11-20 11:29:39 -05:00
|
|
|
spdy_->add_downstream_connection(this);
|
|
|
|
if(spdy_->get_state() == SpdySession::DISCONNECTED) {
|
|
|
|
spdy_->notify();
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
downstream->set_downstream_connection(this);
|
|
|
|
downstream_ = downstream;
|
2012-11-21 09:47:48 -05:00
|
|
|
recv_window_size_ = 0;
|
2012-11-18 07:23:13 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
void SpdyDownstreamConnection::detach_downstream(Downstream *downstream)
|
|
|
|
{
|
|
|
|
if(ENABLE_LOG) {
|
2012-12-09 05:15:14 -05:00
|
|
|
DCLOG(INFO, this) << "Detaching from DOWNSTREAM:" << downstream;
|
2012-11-20 11:29:39 -05:00
|
|
|
}
|
|
|
|
downstream->set_downstream_connection(0);
|
|
|
|
downstream_ = 0;
|
|
|
|
|
|
|
|
// TODO do something to SpdySession? RST_STREAM?
|
|
|
|
|
|
|
|
client_handler_->pool_downstream_connection(this);
|
|
|
|
}
|
|
|
|
|
2012-11-18 07:23:13 -05:00
|
|
|
namespace {
|
|
|
|
ssize_t spdy_data_read_callback(spdylay_session *session,
|
|
|
|
int32_t stream_id,
|
|
|
|
uint8_t *buf, size_t length,
|
|
|
|
int *eof,
|
|
|
|
spdylay_data_source *source,
|
|
|
|
void *user_data)
|
|
|
|
{
|
2012-11-20 11:29:39 -05:00
|
|
|
StreamData *sd;
|
|
|
|
sd = reinterpret_cast<StreamData*>
|
|
|
|
(spdylay_session_get_stream_user_data(session, stream_id));
|
|
|
|
if(!sd || !sd->dconn) {
|
|
|
|
return SPDYLAY_ERR_DEFERRED;
|
|
|
|
}
|
2012-11-18 07:23:13 -05:00
|
|
|
SpdyDownstreamConnection *dconn;
|
|
|
|
dconn = reinterpret_cast<SpdyDownstreamConnection*>(source->ptr);
|
|
|
|
Downstream *downstream = dconn->get_downstream();
|
|
|
|
if(!downstream) {
|
|
|
|
// In this case, RST_STREAM should have been issued. But depending
|
|
|
|
// on the priority, DATA frame may come first.
|
|
|
|
return SPDYLAY_ERR_DEFERRED;
|
|
|
|
}
|
|
|
|
evbuffer *body = dconn->get_request_body_buf();
|
2012-11-20 11:29:39 -05:00
|
|
|
int nread = 0;
|
|
|
|
for(;;) {
|
|
|
|
nread = evbuffer_remove(body, buf, length);
|
|
|
|
if(nread == 0) {
|
|
|
|
if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
|
|
|
|
*eof = 1;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if(downstream->get_upstream()->resume_read(SHRPX_NO_BUFFER) == -1) {
|
|
|
|
// In this case, downstream may be deleted.
|
|
|
|
return SPDYLAY_ERR_DEFERRED;
|
|
|
|
}
|
|
|
|
if(evbuffer_get_length(body) == 0) {
|
|
|
|
return SPDYLAY_ERR_DEFERRED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
return nread;
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2012-11-19 07:40:59 -05:00
|
|
|
namespace {
|
|
|
|
void copy_url_component(std::string& dest, http_parser_url *u, int field,
|
|
|
|
const char* url)
|
|
|
|
{
|
|
|
|
if(u->field_set & (1 << field)) {
|
|
|
|
dest.assign(url+u->field_data[field].off, u->field_data[field].len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2012-11-18 07:23:13 -05:00
|
|
|
int SpdyDownstreamConnection::push_request_headers()
|
|
|
|
{
|
|
|
|
int rv;
|
2012-11-20 11:29:39 -05:00
|
|
|
if(spdy_->get_state() != SpdySession::CONNECTED) {
|
|
|
|
// The SPDY session to the backend has not been established. This
|
|
|
|
// function will be called again just after it is established.
|
2012-11-18 07:23:13 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(!downstream_) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
size_t nheader = downstream_->get_request_headers().size();
|
2012-11-18 09:04:14 -05:00
|
|
|
// 14 means :method, :scheme, :path, :version and possible via,
|
|
|
|
// x-forwarded-for and x-forwarded-proto header fields. We rename
|
|
|
|
// host header field as :host.
|
|
|
|
const char **nv = new const char*[nheader * 2 + 14 + 1];
|
2012-11-18 07:23:13 -05:00
|
|
|
size_t hdidx = 0;
|
|
|
|
std::string via_value;
|
2012-11-18 09:04:14 -05:00
|
|
|
std::string xff_value;
|
2012-11-19 07:40:59 -05:00
|
|
|
std::string scheme, path, query;
|
|
|
|
if(downstream_->get_request_method() != "CONNECT") {
|
|
|
|
http_parser_url u;
|
|
|
|
const char *url = downstream_->get_request_path().c_str();
|
|
|
|
memset(&u, 0, sizeof(u));
|
|
|
|
rv = http_parser_parse_url(url,
|
|
|
|
downstream_->get_request_path().size(),
|
|
|
|
0, &u);
|
|
|
|
if(rv == 0) {
|
|
|
|
copy_url_component(scheme, &u, UF_SCHEMA, url);
|
|
|
|
copy_url_component(path, &u, UF_PATH, url);
|
|
|
|
copy_url_component(query, &u, UF_QUERY, url);
|
|
|
|
if(!query.empty()) {
|
|
|
|
path += "?";
|
|
|
|
path += query;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-18 07:23:13 -05:00
|
|
|
nv[hdidx++] = ":method";
|
|
|
|
nv[hdidx++] = downstream_->get_request_method().c_str();
|
|
|
|
nv[hdidx++] = ":scheme";
|
2012-11-19 07:40:59 -05:00
|
|
|
if(scheme.empty()) {
|
|
|
|
// Currently, the user of this downstream connecion is HTTP
|
|
|
|
// only.
|
|
|
|
nv[hdidx++] = "http";
|
|
|
|
} else {
|
|
|
|
nv[hdidx++] = scheme.c_str();
|
|
|
|
}
|
2012-11-18 07:23:13 -05:00
|
|
|
nv[hdidx++] = ":path";
|
2012-11-19 07:40:59 -05:00
|
|
|
if(downstream_->get_request_method() == "CONNECT" || path.empty()) {
|
|
|
|
nv[hdidx++] = downstream_->get_request_path().c_str();
|
|
|
|
} else {
|
|
|
|
nv[hdidx++] = path.c_str();
|
|
|
|
}
|
2012-11-18 07:23:13 -05:00
|
|
|
nv[hdidx++] = ":version";
|
|
|
|
nv[hdidx++] = "HTTP/1.1";
|
|
|
|
bool chunked_encoding = false;
|
|
|
|
bool content_length = false;
|
|
|
|
for(Headers::const_iterator i = downstream_->get_request_headers().begin();
|
|
|
|
i != downstream_->get_request_headers().end(); ++i) {
|
|
|
|
if(util::strieq((*i).first.c_str(), "transfer-encoding")) {
|
|
|
|
if(util::strieq((*i).second.c_str(), "chunked")) {
|
|
|
|
chunked_encoding = true;
|
|
|
|
}
|
|
|
|
// Ignore transfer-encoding
|
2012-11-18 09:04:14 -05:00
|
|
|
} else if(util::strieq((*i).first.c_str(), "x-forwarded-proto") ||
|
|
|
|
util::strieq((*i).first.c_str(), "keep-alive") ||
|
2012-11-18 07:23:13 -05:00
|
|
|
util::strieq((*i).first.c_str(), "connection") ||
|
|
|
|
util:: strieq((*i).first.c_str(), "proxy-connection")) {
|
|
|
|
// These are ignored
|
|
|
|
} else if(util::strieq((*i).first.c_str(), "via")) {
|
|
|
|
via_value = (*i).second;
|
2012-11-18 09:04:14 -05:00
|
|
|
} else if(util::strieq((*i).first.c_str(), "x-forwarded-for")) {
|
|
|
|
xff_value = (*i).second;
|
2012-11-18 09:49:41 -05:00
|
|
|
} else if(util::strieq((*i).first.c_str(), "expect") &&
|
|
|
|
util::strifind((*i).second.c_str(), "100-continue")) {
|
|
|
|
// Ignore
|
2012-11-18 07:23:13 -05:00
|
|
|
} else if(util::strieq((*i).first.c_str(), "host")) {
|
|
|
|
nv[hdidx++] = ":host";
|
|
|
|
nv[hdidx++] = (*i).second.c_str();
|
|
|
|
} else {
|
|
|
|
if(util::strieq((*i).first.c_str(), "content-length")) {
|
|
|
|
content_length = true;
|
|
|
|
}
|
|
|
|
nv[hdidx++] = (*i).first.c_str();
|
|
|
|
nv[hdidx++] = (*i).second.c_str();
|
|
|
|
}
|
|
|
|
}
|
2012-11-18 09:04:14 -05:00
|
|
|
|
|
|
|
if(get_config()->add_x_forwarded_for) {
|
|
|
|
nv[hdidx++] = "x-forwarded-for";
|
|
|
|
if(!xff_value.empty()) {
|
|
|
|
xff_value += ", ";
|
|
|
|
}
|
|
|
|
xff_value += downstream_->get_upstream()->get_client_handler()->
|
|
|
|
get_ipaddr();
|
|
|
|
nv[hdidx++] = xff_value.c_str();
|
|
|
|
} else if(!xff_value.empty()) {
|
|
|
|
nv[hdidx++] = "x-forwarded-for";
|
|
|
|
nv[hdidx++] = xff_value.c_str();
|
|
|
|
}
|
|
|
|
if(downstream_->get_request_method() != "CONNECT") {
|
|
|
|
// Currently, HTTP connection is used as upstream, so we just
|
|
|
|
// specify it here.
|
|
|
|
nv[hdidx++] = "x-forwarded-proto";
|
|
|
|
nv[hdidx++] = "http";
|
|
|
|
}
|
|
|
|
|
2012-11-18 07:23:13 -05:00
|
|
|
if(!via_value.empty()) {
|
|
|
|
via_value += ", ";
|
|
|
|
}
|
|
|
|
via_value += http::create_via_header_value(downstream_->get_request_major(),
|
|
|
|
downstream_->get_request_minor());
|
|
|
|
nv[hdidx++] = "via";
|
|
|
|
nv[hdidx++] = via_value.c_str();
|
|
|
|
nv[hdidx++] = 0;
|
|
|
|
if(ENABLE_LOG) {
|
|
|
|
std::stringstream ss;
|
|
|
|
for(size_t i = 0; nv[i]; i += 2) {
|
2012-12-09 07:36:02 -05:00
|
|
|
ss << TTY_HTTP_HD << nv[i] << TTY_RST << ": " << nv[i+1] << "\n";
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
2012-12-09 05:15:14 -05:00
|
|
|
DCLOG(INFO, this) << "HTTP request headers\n" << ss.str();
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
2012-11-19 07:40:59 -05:00
|
|
|
if(downstream_->get_request_method() == "CONNECT" ||
|
|
|
|
chunked_encoding || content_length) {
|
2012-11-18 07:23:13 -05:00
|
|
|
// Request-body is expected.
|
|
|
|
spdylay_data_provider data_prd;
|
|
|
|
data_prd.source.ptr = this;
|
|
|
|
data_prd.read_callback = spdy_data_read_callback;
|
2012-11-20 11:29:39 -05:00
|
|
|
rv = spdy_->submit_request(this, 0, nv, &data_prd);
|
2012-11-18 07:23:13 -05:00
|
|
|
} else {
|
2012-11-20 11:29:39 -05:00
|
|
|
rv = spdy_->submit_request(this, 0, nv, 0);
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
delete [] nv;
|
|
|
|
if(rv != 0) {
|
2012-12-09 05:15:14 -05:00
|
|
|
DCLOG(FATAL, this) << "spdylay_submit_request() failed";
|
2012-11-18 07:23:13 -05:00
|
|
|
return -1;
|
|
|
|
}
|
2012-11-20 11:29:39 -05:00
|
|
|
spdy_->notify();
|
|
|
|
return 0;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int SpdyDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
|
|
|
|
size_t datalen)
|
|
|
|
{
|
|
|
|
int rv = evbuffer_add(request_body_buf_, data, datalen);
|
|
|
|
if(rv != 0) {
|
2012-12-09 05:15:14 -05:00
|
|
|
DCLOG(FATAL, this) << "evbuffer_add() failed";
|
2012-11-18 07:23:13 -05:00
|
|
|
return -1;
|
|
|
|
}
|
2012-11-18 09:48:55 -05:00
|
|
|
if(downstream_->get_downstream_stream_id() != -1) {
|
2012-11-20 11:29:39 -05:00
|
|
|
rv = spdy_->resume_data(this);
|
2012-11-18 12:11:46 -05:00
|
|
|
if(rv != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2012-11-20 11:29:39 -05:00
|
|
|
spdy_->notify();
|
2012-11-18 12:11:46 -05:00
|
|
|
}
|
|
|
|
return 0;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int SpdyDownstreamConnection::end_upload_data()
|
|
|
|
{
|
|
|
|
int rv;
|
2012-11-20 11:29:39 -05:00
|
|
|
if(downstream_->get_downstream_stream_id() != -1) {
|
|
|
|
rv = spdy_->resume_data(this);
|
2012-11-18 07:23:13 -05:00
|
|
|
if(rv != 0) {
|
2012-11-20 11:29:39 -05:00
|
|
|
return -1;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
2012-11-20 11:29:39 -05:00
|
|
|
spdy_->notify();
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
2012-11-20 11:29:39 -05:00
|
|
|
return 0;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
int SpdyDownstreamConnection::on_read()
|
2012-11-18 07:23:13 -05:00
|
|
|
{
|
2012-11-20 11:29:39 -05:00
|
|
|
return 0;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
int SpdyDownstreamConnection::on_write()
|
2012-11-18 07:23:13 -05:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-21 09:47:48 -05:00
|
|
|
int SpdyDownstreamConnection::on_upstream_write()
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
if(spdy_->get_state() == SpdySession::CONNECTED &&
|
|
|
|
spdy_->get_flow_control() &&
|
|
|
|
downstream_ && downstream_->get_downstream_stream_id() != -1 &&
|
|
|
|
recv_window_size_ >= spdy_->get_initial_window_size()/2) {
|
|
|
|
rv = spdy_->submit_window_update(this, recv_window_size_);
|
|
|
|
if(rv == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
spdy_->notify();
|
|
|
|
recv_window_size_ = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
evbuffer* SpdyDownstreamConnection::get_request_body_buf() const
|
2012-11-18 07:23:13 -05:00
|
|
|
{
|
2012-11-20 11:29:39 -05:00
|
|
|
return request_body_buf_;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
void SpdyDownstreamConnection::attach_stream_data(StreamData *sd)
|
2012-11-18 07:23:13 -05:00
|
|
|
{
|
2012-11-20 11:29:39 -05:00
|
|
|
assert(sd_ == 0 && sd->dconn == 0);
|
|
|
|
sd_ = sd;
|
|
|
|
sd_->dconn = this;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
StreamData* SpdyDownstreamConnection::detach_stream_data()
|
2012-11-18 07:23:13 -05:00
|
|
|
{
|
2012-11-20 11:29:39 -05:00
|
|
|
if(sd_) {
|
|
|
|
StreamData *sd = sd_;
|
|
|
|
sd_ = 0;
|
|
|
|
sd->dconn = 0;
|
|
|
|
return sd;
|
|
|
|
} else {
|
|
|
|
return 0;
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-20 11:29:39 -05:00
|
|
|
bool SpdyDownstreamConnection::get_output_buffer_full()
|
2012-11-18 07:23:13 -05:00
|
|
|
{
|
2012-11-20 11:29:39 -05:00
|
|
|
if(request_body_buf_) {
|
|
|
|
return
|
|
|
|
evbuffer_get_length(request_body_buf_) >= Downstream::OUTPUT_UPPER_THRES;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2012-11-18 07:23:13 -05:00
|
|
|
}
|
|
|
|
|
2012-11-21 09:47:48 -05:00
|
|
|
int32_t SpdyDownstreamConnection::get_recv_window_size() const
|
|
|
|
{
|
|
|
|
return recv_window_size_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpdyDownstreamConnection::inc_recv_window_size(int32_t amount)
|
|
|
|
{
|
|
|
|
recv_window_size_ += amount;
|
|
|
|
}
|
|
|
|
|
2012-11-18 07:23:13 -05:00
|
|
|
} // namespace shrpx
|