blob: c0363fc7ff077bf55a1f04185a17a019745b9cb4 [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 "TEvhttpClientChannel.h"
21#include <evhttp.h>
Roger Meier7e056e72011-07-17 07:28:28 +000022#include "transport/TBufferTransports.h"
Roger Meier08077bf2011-09-11 07:28:54 +000023#include <protocol/TProtocolException.h>
24
25#include <iostream>
26#include <sstream>
27
28using namespace apache::thrift::protocol;
29using apache::thrift::transport::TTransportException;
David Reiss5ddabb82010-10-06 17:09:37 +000030
31namespace apache { namespace thrift { namespace async {
32
33
34TEvhttpClientChannel::TEvhttpClientChannel(
35 const std::string& host,
36 const std::string& path,
37 const char* address,
38 int port,
39 struct event_base* eb)
40 : host_(host)
41 , path_(path)
42 , recvBuf_(NULL)
43 , conn_(NULL)
44{
45 conn_ = evhttp_connection_new(address, port);
46 if (conn_ == NULL) {
Roger Meier08077bf2011-09-11 07:28:54 +000047 throw TException("evhttp_connection_new failed");
David Reiss5ddabb82010-10-06 17:09:37 +000048 }
49 evhttp_connection_set_base(conn_, eb);
50}
51
52
53TEvhttpClientChannel::~TEvhttpClientChannel() {
54 if (conn_ != NULL) {
55 evhttp_connection_free(conn_);
56 }
57}
58
59
Roger Meier285cfaa2011-07-28 17:51:36 +000060void TEvhttpClientChannel::sendAndRecvMessage(
David Reiss5ddabb82010-10-06 17:09:37 +000061 const VoidCallback& cob,
62 apache::thrift::transport::TMemoryBuffer* sendBuf,
63 apache::thrift::transport::TMemoryBuffer* recvBuf) {
64 cob_ = cob;
65 recvBuf_ = recvBuf;
66
67 struct evhttp_request* req = evhttp_request_new(response, this);
68 if (req == NULL) {
Roger Meier08077bf2011-09-11 07:28:54 +000069 throw TException("evhttp_request_new failed");
David Reiss5ddabb82010-10-06 17:09:37 +000070 }
71
72 int rv;
73
74 rv = evhttp_add_header(req->output_headers, "Host", host_.c_str());
75 if (rv != 0) {
Roger Meier08077bf2011-09-11 07:28:54 +000076 throw TException("evhttp_add_header failed");
David Reiss5ddabb82010-10-06 17:09:37 +000077 }
78
79 rv = evhttp_add_header(req->output_headers, "Content-Type", "application/x-thrift");
80 if (rv != 0) {
Roger Meier08077bf2011-09-11 07:28:54 +000081 throw TException("evhttp_add_header failed");
David Reiss5ddabb82010-10-06 17:09:37 +000082 }
83
84 uint8_t* obuf;
85 uint32_t sz;
86 sendBuf->getBuffer(&obuf, &sz);
87 rv = evbuffer_add(req->output_buffer, obuf, sz);
88 if (rv != 0) {
Roger Meier08077bf2011-09-11 07:28:54 +000089 throw TException("evbuffer_add failed");
David Reiss5ddabb82010-10-06 17:09:37 +000090 }
91
92 rv = evhttp_make_request(conn_, req, EVHTTP_REQ_POST, path_.c_str());
93 if (rv != 0) {
Roger Meier08077bf2011-09-11 07:28:54 +000094 throw TException("evhttp_make_request failed");
David Reiss5ddabb82010-10-06 17:09:37 +000095 }
David Reiss5ddabb82010-10-06 17:09:37 +000096}
97
98
Roger Meier285cfaa2011-07-28 17:51:36 +000099void TEvhttpClientChannel::sendMessage(
David Reiss5ddabb82010-10-06 17:09:37 +0000100 const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) {
Roger Meiera8cef6e2011-07-17 18:55:59 +0000101 (void) cob;
102 (void) message;
Roger Meier08077bf2011-09-11 07:28:54 +0000103 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
104 "Unexpected call to TEvhttpClientChannel::sendMessage");
David Reiss5ddabb82010-10-06 17:09:37 +0000105}
106
107
Roger Meier285cfaa2011-07-28 17:51:36 +0000108void TEvhttpClientChannel::recvMessage(
David Reiss5ddabb82010-10-06 17:09:37 +0000109 const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) {
Roger Meiera8cef6e2011-07-17 18:55:59 +0000110 (void) cob;
111 (void) message;
Roger Meier08077bf2011-09-11 07:28:54 +0000112 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
113 "Unexpected call to TEvhttpClientChannel::recvMessage");
David Reiss5ddabb82010-10-06 17:09:37 +0000114}
115
116
117void TEvhttpClientChannel::finish(struct evhttp_request* req) {
118 if (req == NULL) {
Roger Meier08077bf2011-09-11 07:28:54 +0000119 try {
Roger Meier285cfaa2011-07-28 17:51:36 +0000120 cob_();
Roger Meier08077bf2011-09-11 07:28:54 +0000121 } catch(const TTransportException& e) {
122 if(e.getType() == TTransportException::END_OF_FILE)
123 throw TException("connect failed");
124 else
125 throw;
126 }
127 return;
David Reiss5ddabb82010-10-06 17:09:37 +0000128 } else if (req->response_code != 200) {
Roger Meier08077bf2011-09-11 07:28:54 +0000129 try {
Roger Meier285cfaa2011-07-28 17:51:36 +0000130 cob_();
Roger Meier08077bf2011-09-11 07:28:54 +0000131 } catch(const TTransportException& e) {
132 std::stringstream ss;
133 ss << "server returned code " << req->response_code;
134 if(req->response_code_line)
135 ss << ": " << req->response_code_line;
136 if(e.getType() == TTransportException::END_OF_FILE)
137 throw TException(ss.str());
138 else
139 throw;
140 }
141 return;
David Reiss5ddabb82010-10-06 17:09:37 +0000142 }
143 recvBuf_->resetBuffer(
144 EVBUFFER_DATA(req->input_buffer),
145 EVBUFFER_LENGTH(req->input_buffer));
Roger Meier285cfaa2011-07-28 17:51:36 +0000146 cob_();
147 return;
David Reiss5ddabb82010-10-06 17:09:37 +0000148}
149
150
151/* static */ void TEvhttpClientChannel::response(struct evhttp_request* req, void* arg) {
152 TEvhttpClientChannel* self = (TEvhttpClientChannel*)arg;
Roger Meier08077bf2011-09-11 07:28:54 +0000153 try {
154 self->finish(req);
155 } catch(std::exception& e) {
156 // don't propagate a C++ exception in C code (e.g. libevent)
157 std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what() << std::endl;
158 }
David Reiss5ddabb82010-10-06 17:09:37 +0000159}
160
161
162}}} // apache::thrift::async