blob: 701f8bd0e5a49f6c6e071665a5b9f435cb05e214 [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
Roger Meier7e056e72011-07-17 07:28:28 +000025#ifndef HTTP_INTERNAL // libevent < 2
26#define HTTP_INTERNAL 500
27#endif
28
David Reiss5ddabb82010-10-06 17:09:37 +000029using apache::thrift::transport::TMemoryBuffer;
30
31namespace apache { namespace thrift { namespace async {
32
33
34struct TEvhttpServer::RequestContext {
35 struct evhttp_request* req;
36 boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> ibuf;
37 boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> obuf;
38
39 RequestContext(struct evhttp_request* req);
40};
41
42
43TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor)
44 : processor_(processor)
45 , eb_(NULL)
46 , eh_(NULL)
47{}
48
49
50TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port)
51 : processor_(processor)
52 , eb_(NULL)
53 , eh_(NULL)
54{
55 // Create event_base and evhttp.
56 eb_ = event_base_new();
57 if (eb_ == NULL) {
58 abort(); // XXX
59 }
60 eh_ = evhttp_new(eb_);
61 if (eh_ == NULL) {
62 event_base_free(eb_);
63 abort(); // XXX
64 }
65
66 // Bind to port.
67 int ret = evhttp_bind_socket(eh_, NULL, port);
68 if (ret < 0) {
69 evhttp_free(eh_);
70 event_base_free(eb_);
71 }
72
73 // Register a handler. If you use the other constructor,
74 // you will want to do this yourself.
75 // Don't forget to unregister before destorying this TEvhttpServer.
76 evhttp_set_cb(eh_, "/", request, (void*)this);
77}
78
79
80TEvhttpServer::~TEvhttpServer() {
81 if (eh_ != NULL) {
82 evhttp_free(eh_);
83 }
84 if (eb_ != NULL) {
85 event_base_free(eb_);
86 }
87}
88
89
90int TEvhttpServer::serve() {
91 if (eb_ == NULL) {
92 abort(); // XXX
93 }
94 return event_base_dispatch(eb_);
95}
96
97
98TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req) : req(req)
99 , ibuf(new TMemoryBuffer(EVBUFFER_DATA(req->input_buffer), EVBUFFER_LENGTH(req->input_buffer)))
100 , obuf(new TMemoryBuffer())
101{}
102
103
104void TEvhttpServer::request(struct evhttp_request* req, void* self) {
Roger Meier7e056e72011-07-17 07:28:28 +0000105 try {
106 static_cast<TEvhttpServer*>(self)->process(req);
107 } catch(std::exception& e) {
108 evhttp_send_reply(req, HTTP_INTERNAL, e.what(), 0);
109 }
David Reiss5ddabb82010-10-06 17:09:37 +0000110}
111
112
113void TEvhttpServer::process(struct evhttp_request* req) {
114 RequestContext* ctx = new RequestContext(req);
115 return processor_->process(
116 std::tr1::bind(
117 &TEvhttpServer::complete,
118 this,
119 ctx,
120 std::tr1::placeholders::_1),
121 ctx->ibuf,
122 ctx->obuf);
123}
124
125
126void TEvhttpServer::complete(RequestContext* ctx, bool success) {
Roger Meiera8cef6e2011-07-17 18:55:59 +0000127 (void) success;
David Reiss5ddabb82010-10-06 17:09:37 +0000128 std::auto_ptr<RequestContext> ptr(ctx);
129
130 int code = 200;
131 const char* reason = "OK";
132
133 int rv = evhttp_add_header(ctx->req->output_headers, "Content-Type", "application/x-thrift");
134 if (rv != 0) {
135 // TODO: Log an error.
136 }
137
138 struct evbuffer* buf = evbuffer_new();
139 if (buf == NULL) {
140 // TODO: Log an error.
141 } else {
142 uint8_t* obuf;
143 uint32_t sz;
144 ctx->obuf->getBuffer(&obuf, &sz);
145 int ret = evbuffer_add(buf, obuf, sz);
146 if (ret != 0) {
147 // TODO: Log an error.
148 }
149 }
150
151 evhttp_send_reply(ctx->req, code, reason, buf);
152 if (buf != NULL) {
153 evbuffer_free(buf);
154 }
155}
156
157
158struct event_base* TEvhttpServer::getEventBase() {
159 return eb_;
160}
161
162
163}}} // apache::thrift::async