]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | %% |
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 | -module(thrift_http_transport). | |
21 | ||
22 | -behaviour(thrift_transport). | |
23 | ||
24 | %% API | |
25 | -export([new/2, new/3]). | |
26 | ||
27 | %% thrift_transport callbacks | |
28 | -export([write/2, read/2, flush/1, close/1]). | |
29 | ||
30 | -record(http_transport, {host, % string() | |
31 | path, % string() | |
32 | read_buffer, % iolist() | |
33 | write_buffer, % iolist() | |
34 | http_options, % see http(3) | |
35 | extra_headers % [{str(), str()}, ...] | |
36 | }). | |
37 | -type state() :: #http_transport{}. | |
38 | -include("thrift_transport_behaviour.hrl"). | |
39 | ||
40 | new(Host, Path) -> | |
41 | new(Host, Path, _Options = []). | |
42 | ||
43 | %%-------------------------------------------------------------------- | |
44 | %% Options include: | |
45 | %% {http_options, HttpOptions} = See http(3) | |
46 | %% {extra_headers, ExtraHeaders} = List of extra HTTP headers | |
47 | %%-------------------------------------------------------------------- | |
48 | new(Host, Path, Options) -> | |
49 | State1 = #http_transport{host = Host, | |
50 | path = Path, | |
51 | read_buffer = [], | |
52 | write_buffer = [], | |
53 | http_options = [], | |
54 | extra_headers = []}, | |
55 | ApplyOption = | |
56 | fun | |
57 | ({http_options, HttpOpts}, State = #http_transport{}) -> | |
58 | State#http_transport{http_options = HttpOpts}; | |
59 | ({extra_headers, ExtraHeaders}, State = #http_transport{}) -> | |
60 | State#http_transport{extra_headers = ExtraHeaders}; | |
61 | (Other, #http_transport{}) -> | |
62 | {invalid_option, Other}; | |
63 | (_, Error) -> | |
64 | Error | |
65 | end, | |
66 | case lists:foldl(ApplyOption, State1, Options) of | |
67 | State2 = #http_transport{} -> | |
68 | thrift_transport:new(?MODULE, State2); | |
69 | Else -> | |
70 | {error, Else} | |
71 | end. | |
72 | ||
73 | %% Writes data into the buffer | |
74 | write(State = #http_transport{write_buffer = WBuf}, Data) -> | |
75 | {State#http_transport{write_buffer = [WBuf, Data]}, ok}. | |
76 | ||
77 | %% Flushes the buffer, making a request | |
78 | flush(State = #http_transport{host = Host, | |
79 | path = Path, | |
80 | read_buffer = Rbuf, | |
81 | write_buffer = Wbuf, | |
82 | http_options = HttpOptions, | |
83 | extra_headers = ExtraHeaders}) -> | |
84 | case iolist_to_binary(Wbuf) of | |
85 | <<>> -> | |
86 | %% Don't bother flushing empty buffers. | |
87 | {State, ok}; | |
88 | WBinary -> | |
89 | {ok, {{_Version, 200, _ReasonPhrase}, _Headers, Body}} = | |
90 | httpc:request(post, | |
91 | {"http://" ++ Host ++ Path, | |
92 | [{"User-Agent", "Erlang/thrift_http_transport"} | ExtraHeaders], | |
93 | "application/x-thrift", | |
94 | WBinary}, | |
95 | HttpOptions, | |
96 | [{body_format, binary}]), | |
97 | ||
98 | State1 = State#http_transport{read_buffer = [Rbuf, Body], | |
99 | write_buffer = []}, | |
100 | {State1, ok} | |
101 | end. | |
102 | ||
103 | close(State) -> | |
104 | {State, ok}. | |
105 | ||
106 | read(State = #http_transport{read_buffer = RBuf}, Len) when is_integer(Len) -> | |
107 | %% Pull off Give bytes, return them to the user, leave the rest in the buffer. | |
108 | Give = min(iolist_size(RBuf), Len), | |
109 | case iolist_to_binary(RBuf) of | |
110 | <<Data:Give/binary, RBuf1/binary>> -> | |
111 | Response = {ok, Data}, | |
112 | State1 = State#http_transport{read_buffer=RBuf1}, | |
113 | {State1, Response}; | |
114 | _ -> | |
115 | {State, {error, 'EOF'}} | |
116 | end. |