%% @author Bob Ippolito %% @copyright 2007 Mochi Media, Inc. %% %% 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. %% @doc Response abstraction. -module(mochiweb_response). -author('bob@mochimedia.com'). -define(QUIP, "Any of you quaids got a smint?"). -export([new/3, get_header_value/2, get/2, dump/1]). -export([send/2, write_chunk/2]). %% @type response(). A mochiweb_response parameterized module instance. %% @spec new(Request, Code, Headers) -> response() %% @doc Create a new mochiweb_response instance. new(Request, Code, Headers) -> {?MODULE, [Request, Code, Headers]}. %% @spec get_header_value(string() | atom() | binary(), response()) -> %% string() | undefined %% @doc Get the value of the given response header. get_header_value(K, {?MODULE, [_Request, _Code, Headers]}) -> mochiweb_headers:get_value(K, Headers). %% @spec get(request | code | headers, response()) -> term() %% @doc Return the internal representation of the given field. get(request, {?MODULE, [Request, _Code, _Headers]}) -> Request; get(code, {?MODULE, [_Request, Code, _Headers]}) -> Code; get(headers, {?MODULE, [_Request, _Code, Headers]}) -> Headers. %% @spec dump(response()) -> {mochiweb_request, [{atom(), term()}]} %% @doc Dump the internal representation to a "human readable" set of terms %% for debugging/inspection purposes. dump({?MODULE, [Request, Code, Headers]}) -> [{request, Request:dump()}, {code, Code}, {headers, mochiweb_headers:to_list(Headers)}]. %% @spec send(iodata(), response()) -> ok %% @doc Send data over the socket if the method is not HEAD. send(Data, {?MODULE, [Request, _Code, _Headers]}) -> case Request:get(method) of 'HEAD' -> ok; _ -> Request:send(Data) end. %% @spec write_chunk(iodata(), response()) -> ok %% @doc Write a chunk of a HTTP chunked response. If Data is zero length, %% then the chunked response will be finished. write_chunk(Data, {?MODULE, [Request, _Code, _Headers]}=THIS) -> case Request:get(version) of Version when Version >= {1, 1} -> Length = iolist_size(Data), send([io_lib:format("~.16b\r\n", [Length]), Data, <<"\r\n">>], THIS); _ -> send(Data, THIS) end. %% %% Tests %% -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -endif.