aboutsummaryrefslogtreecommitdiffstats
path: root/src/httpabs.erl
blob: 152621e44a393ef99f3717fadd8f1e683cc017db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
% ============LICENSE_START=======================================================
% org.onap.dcae
% ================================================================================
% Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
% ================================================================================
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
%      http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
% ============LICENSE_END=========================================================
%
% ECOMP is a trademark and service mark of AT&T Intellectual Property.

-module(httpabs).
-export([get/2,
         post/4, %I miss python's default arguments..
         post/5,
         put/4,
         delete/2
        ]).
-include("application.hrl").
-define(SC(L), util:concat(L)).

%NOTE
%Consider the Erlang statement:
%
%{ok, {{"HTTP/1.1",ReturnCode, State}, Head, Body}} = httpc:get(URL).
%CDAP returns error messages in the “Body” field above.
%
%However, Consul:
%1) Always (in all HTTP failures I’ve tested) returns Body == “500\n”
%2) Returns the error message in the State field
%
%Example:
%
%{{"HTTP/1.0",404,"Client Error: Not Found for url: http://consul.[...].com:8500/v1/kv/hwtestYOUHAVEFAILEDME:rel"},[{"date","Mon, 14 Nov 2016 14:41:03 GMT"},{"server","Werkzeug/0.11.11 Python/3.5.1"},{"content-length","4"},{"content-type","application/json"}],"500\n"}
%
%This means that error handling in HTTP is not consistent across CDAP and Consul.
%
%Thus below, on a failure, I return the concatenation of State and Body

%%%
%%%HELPER
%%%
-spec parse_response({error|ok, any()}, string()) -> httpstat().
parse_response({Status, Response}, URL) ->
    case Status of
        error ->
            lager:error("httpc error: cannot hit: ~s", [URL]),
            case Response of
                no_scheme               -> {400, io_lib:format("ERROR: The following URL is malformed: ~s", [URL])};
                {bad_body, _}           -> {400, "ERROR: The request Body is malformed"};
                {bad_body_generator,_}  -> {400, "ERROR: The request Body is malformed"};
                _  ->
                    lager:error(io_lib:format("Unexpected ERROR hitting ~s", [URL])),
                    {504, list_to_binary(io_lib:format("ERROR: The following URL is unreachable or the request was unable to be parsed due to an unknown error: ~s", [URL]))} %Are there other reasons other than bad body and unreachable that crash request? (Sneak peak: the answer is probably)
            end;
        ok ->
            {{_, ReturnCode, State}, _Head, Body} = Response,
            case ReturnCode of
                200 ->
                    {ReturnCode, Body};
                _ ->
                    lager:error("Error While hitting ~s, Non-200 status code returned. HTTP Code ~p, State ~s, ResponseBody ~s:", [URL, ReturnCode, State, Body]),
                    %see Note at the top of this file
                    RetBody = ?SC(["State: ", State, ". Return Body: ", Body]),
                    {ReturnCode, RetBody}
            end
    end.

sanitize(URL) ->
    %allow URL to look like "www.foo.com" or <<"www.foo.com">>, trim it
    case is_binary(URL) of
        true -> string:strip(binary_to_list(URL));
        false -> string:strip(URL)
    end.

%anywhere you see any() is essentially lazy typing.. fix these someday when time is abundant
-spec post(string(), string()|binary(), string(), any()) -> httpstat().
post(XER, URL, ContentType, Body) ->
    %post that sends the XER, no headers signature
    Headers = [{"x-ecomp-requestid", XER}],
    U = sanitize(URL),
    parse_response(httpc:request(post, {U, Headers, ContentType, Body}, [],[]), U).

-spec post(string(), string()|binary(), list(), string(), any()) -> httpstat().
post(XER, URL, Headers, ContentType, Body) ->
    %post that sends XER, appends the header onto the list of desired headers
    U = sanitize(URL),
    parse_response(httpc:request(post, {U, [{"x-ecomp-requestid", XER} | Headers], ContentType, Body}, [],[]), U).

-spec get(string(), string()|binary()) -> httpstat().
get(XER, URL) ->
    %http get that always sends the XER.. even if the server doesn't want it; maybe this will blow up on me one day.
    U = sanitize(URL),
    Headers = [{"x-ecomp-requestid", XER}],
    parse_response(httpc:request(get, {U, Headers}, [], []), U).

-spec put(string(), string()|binary(), string(), any()) -> httpstat().
put(XER, URL, ContentType, Body) ->
    %http put that always sends the XER
    U = sanitize(URL),
    Headers = [{"x-ecomp-requestid", XER}],
    parse_response(httpc:request(put, {U, Headers, ContentType, Body}, [],[]), U).

-spec delete(string(), string()|binary()) -> httpstat().
delete(XER, URL) ->
    %http delete that always sends the XER
    U = sanitize(URL),
    Headers = [{"x-ecomp-requestid", XER}],
    parse_response(httpc:request(delete, {U, Headers}, [],[]), U).