blob: 2997597139b7454e86709e4b82fbe8f384c3f019 [file] [log] [blame]
David Reiss5ddabb82010-10-06 17:09:37 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#include "TEvhttpServer.h"
21#include "TAsyncBufferProcessor.h"
22#include "transport/TBufferTransports.h"
23#include <evhttp.h>
24
25using apache::thrift::transport::TMemoryBuffer;
26
27namespace apache { namespace thrift { namespace async {
28
29
30struct TEvhttpServer::RequestContext {
31 struct evhttp_request* req;
32 boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> ibuf;
33 boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> obuf;
34
35 RequestContext(struct evhttp_request* req);
36};
37
38
39TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor)
40 : processor_(processor)
41 , eb_(NULL)
42 , eh_(NULL)
43{}
44
45
46TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port)
47 : processor_(processor)
48 , eb_(NULL)
49 , eh_(NULL)
50{
51 // Create event_base and evhttp.
52 eb_ = event_base_new();
53 if (eb_ == NULL) {
54 abort(); // XXX
55 }
56 eh_ = evhttp_new(eb_);
57 if (eh_ == NULL) {
58 event_base_free(eb_);
59 abort(); // XXX
60 }
61
62 // Bind to port.
63 int ret = evhttp_bind_socket(eh_, NULL, port);
64 if (ret < 0) {
65 evhttp_free(eh_);
66 event_base_free(eb_);
67 }
68
69 // Register a handler. If you use the other constructor,
70 // you will want to do this yourself.
71 // Don't forget to unregister before destorying this TEvhttpServer.
72 evhttp_set_cb(eh_, "/", request, (void*)this);
73}
74
75
76TEvhttpServer::~TEvhttpServer() {
77 if (eh_ != NULL) {
78 evhttp_free(eh_);
79 }
80 if (eb_ != NULL) {
81 event_base_free(eb_);
82 }
83}
84
85
86int TEvhttpServer::serve() {
87 if (eb_ == NULL) {
88 abort(); // XXX
89 }
90 return event_base_dispatch(eb_);
91}
92
93
94TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req) : req(req)
95 , ibuf(new TMemoryBuffer(EVBUFFER_DATA(req->input_buffer), EVBUFFER_LENGTH(req->input_buffer)))
96 , obuf(new TMemoryBuffer())
97{}
98
99
100void TEvhttpServer::request(struct evhttp_request* req, void* self) {
101 static_cast<TEvhttpServer*>(self)->process(req);
102}
103
104
105void TEvhttpServer::process(struct evhttp_request* req) {
106 RequestContext* ctx = new RequestContext(req);
107 return processor_->process(
108 std::tr1::bind(
109 &TEvhttpServer::complete,
110 this,
111 ctx,
112 std::tr1::placeholders::_1),
113 ctx->ibuf,
114 ctx->obuf);
115}
116
117
118void TEvhttpServer::complete(RequestContext* ctx, bool success) {
119 std::auto_ptr<RequestContext> ptr(ctx);
120
121 int code = 200;
122 const char* reason = "OK";
123
124 int rv = evhttp_add_header(ctx->req->output_headers, "Content-Type", "application/x-thrift");
125 if (rv != 0) {
126 // TODO: Log an error.
127 }
128
129 struct evbuffer* buf = evbuffer_new();
130 if (buf == NULL) {
131 // TODO: Log an error.
132 } else {
133 uint8_t* obuf;
134 uint32_t sz;
135 ctx->obuf->getBuffer(&obuf, &sz);
136 int ret = evbuffer_add(buf, obuf, sz);
137 if (ret != 0) {
138 // TODO: Log an error.
139 }
140 }
141
142 evhttp_send_reply(ctx->req, code, reason, buf);
143 if (buf != NULL) {
144 evbuffer_free(buf);
145 }
146}
147
148
149struct event_base* TEvhttpServer::getEventBase() {
150 return eb_;
151}
152
153
154}}} // apache::thrift::async