Fix socket descritpor leak in http client post
[com/gs-lite.git] / src / lib / gscpaux / simple_http.cpp
1 /* ------------------------------------------------
2 Copyright 2014 AT&T Intellectual Property
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7      http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License.
14  ------------------------------------------- */
15
16 #include <arpa/inet.h>
17 #include <netinet/in.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/wait.h>
24 #include <netdb.h>
25 #include <unistd.h>
26
27 #include "simple_http.h"
28
29 #define MAX_HTTP_REQUEST 64 * 1024
30
31
32 // perform HTTP GET and retrieve the json response
33 int http_get_request(endpoint addr, gs_csp_t url, gs_uint32_t* http_code, gs_sp_t json_response) {
34
35         int sockfd;
36         struct sockaddr_in servaddr;
37         char request_buf[MAX_HTTP_REQUEST];
38         char response_buf[MAX_HTTP_REQUEST];
39         char temp_buf[MAX_HTTP_REQUEST];
40         char content_type[MAX_HTTP_REQUEST];
41         int n;
42
43         char ipstr[16];
44         inet_ntop(AF_INET, &addr.ip, ipstr, INET_ADDRSTRLEN);
45
46         sockfd = socket(AF_INET, SOCK_STREAM, 0);
47         if (!sockfd) {
48                 fprintf(stderr, "Unable to create socket for HTTP connection\n");
49                 return -1;
50         }
51
52         bzero(&servaddr, sizeof(servaddr));
53         servaddr.sin_family = AF_INET;
54         servaddr.sin_port = addr.port;
55         servaddr.sin_addr.s_addr = addr.ip;
56
57         if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr))) {
58                 fprintf(stderr, "Unable to connect to HTTP server\n");
59                 close(sockfd);
60                 return -1;
61         }
62
63         // construct HTTP request
64         sprintf(request_buf, "GET %s HTTP/1.0\r\n"
65                         "Host: %s\r\n"
66                         "Accept: application/json\r\n"
67                         "Connection: close\r\n\r\n",
68                         url, ipstr);
69
70         write(sockfd, request_buf, strlen(request_buf));
71
72         // retrive HTTP response
73         char* write_pos = response_buf;
74         while ((n = read(sockfd, write_pos, MAX_HTTP_REQUEST)) > 0)
75                 write_pos += n;
76         *write_pos = '\0';
77         close(sockfd);
78
79         // split HTTP response into header and the main body
80         char* header_end = strstr(response_buf, "\r\n\r\n");
81         *header_end = 0;
82         strcpy(json_response, header_end + 4);
83
84         // parse HTTP header
85         char* header_line = strtok(response_buf, "\r\n");
86         int ver1, ver2;
87
88         // extract http response code
89         sscanf (header_line, "HTTP/%d.%d %d %s", &ver1, &ver2, http_code, temp_buf);
90
91         // extract content-type
92         *content_type = 0;
93         while ((header_line = strtok(NULL, "\r\n"))) {
94                 if (!strncmp(header_line, "Content-Type: ", strlen("Content-Type: "))) {
95                         strcpy(content_type, header_line + strlen("Content-Type: "));
96                         if (strcmp(content_type, "application/json")) {
97                                 fprintf(stderr, "Invalid Content-Type %s, application/json expected\n", content_type);
98                                 return -1;
99                         }
100                         break;          // we only care about Content-Type headers
101                 }
102         }
103
104         if ((*http_code == 200) && (*content_type == 0)) {
105                 fprintf(stderr, "Missing Content-Type in server response, application/json expected\n");
106                 return -1;
107         }
108
109
110         return 0;
111 }
112
113 // perform HTTP POST request ignoring the response
114 int http_post_request(endpoint addr, gs_csp_t url, gs_sp_t json_request, gs_uint32_t* http_code) {
115         int sockfd;
116         struct sockaddr_in servaddr;
117         char request_buf[MAX_HTTP_REQUEST];
118         char response_buf[MAX_HTTP_REQUEST];
119         char temp_buf[MAX_HTTP_REQUEST];
120         int n;
121
122         char ipstr[16];
123         inet_ntop(AF_INET, &addr.ip, ipstr, INET_ADDRSTRLEN);
124
125         sockfd = socket(AF_INET, SOCK_STREAM, 0);
126         if (!sockfd) {
127                 fprintf(stderr, "Unable to create socket for HTTP connection\n");
128                 return -1;
129         }
130
131         bzero(&servaddr, sizeof(servaddr));
132         servaddr.sin_family = AF_INET;
133         servaddr.sin_port = addr.port;
134         servaddr.sin_addr.s_addr = addr.ip;
135
136         if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr))) {
137                 fprintf(stderr, "Unable to connect to HTTP server\n");
138                 close(sockfd);
139                 return -1;
140         }
141
142         // construct HTTP request
143         sprintf(request_buf, "POST %s HTTP/1.0\r\n"
144                         "Host: %s\r\n"
145                         "Content-Type: application/json\r\n"
146                         "Content-Length: %lu\r\n"
147                         "Connection: close\r\n\r\n"
148                         "%s",
149                         url, ipstr, strlen(json_request), json_request);
150
151         write(sockfd, request_buf, strlen(request_buf));
152
153         // retrive HTTP response
154         char* write_pos = response_buf;
155         while ((n = read(sockfd, write_pos, MAX_HTTP_REQUEST)) > 0)
156                 write_pos += n;
157         *write_pos = '\0';
158         close(sockfd);
159
160         // parse HTTP header
161         char* header_line = strtok(response_buf, "\r\n");
162         int ver1, ver2;
163
164         // extract http response code
165         sscanf (header_line, "HTTP/%d.%d %d %s", &ver1, &ver2, http_code, temp_buf);
166
167         return 0;
168 }
169
170
171 // perform HTTP POST request ignoring the response
172 int http_post_request_hdr(endpoint addr, gs_csp_t url, gs_sp_t json_request, gs_uint32_t* http_code, gs_sp_t extra_headers) {
173         int sockfd;
174         struct sockaddr_in servaddr;
175         char request_buf[MAX_HTTP_REQUEST];
176         char response_buf[MAX_HTTP_REQUEST];
177         char temp_buf[MAX_HTTP_REQUEST];
178         int n;
179
180         char ipstr[16];
181         inet_ntop(AF_INET, &addr.ip, ipstr, INET_ADDRSTRLEN);
182
183         sockfd = socket(AF_INET, SOCK_STREAM, 0);
184         if (!sockfd) {
185                 fprintf(stderr, "Unable to create socket for HTTP connection\n");
186                 return -1;
187         }
188
189         bzero(&servaddr, sizeof(servaddr));
190         servaddr.sin_family = AF_INET;
191         servaddr.sin_port = addr.port;
192         servaddr.sin_addr.s_addr = addr.ip;
193
194         if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr))) {
195                 fprintf(stderr, "Unable to connect to HTTP server\n");
196                 close(sockfd);
197                 return -1;
198         }
199
200         // construct HTTP request
201         if(strlen(extra_headers)==0){
202                 sprintf(request_buf, "POST %s HTTP/1.0\r\n"
203                         "Host: %s\r\n"
204                         "Content-Type: application/json\r\n"
205                         "Content-Length: %lu\r\n"
206                         "\r\n"
207                         "%s",
208                         url, ipstr, strlen(json_request), json_request);
209         }else{
210                 sprintf(request_buf, "POST %s HTTP/1.0\r\n"
211                         "Host: %s\r\n"
212                         "Content-Type: application/json\r\n"
213                         "Content-Length: %lu\r\n"
214                         "%s\r\n\r\n"
215                         "%s",
216                         url, ipstr, strlen(json_request), extra_headers, json_request);
217         }
218
219         write(sockfd, request_buf, strlen(request_buf));
220
221         // retrive HTTP response
222         char* write_pos = response_buf;
223         while ((n = read(sockfd, write_pos, MAX_HTTP_REQUEST)) > 0)
224                 write_pos += n;
225         *write_pos = '\0';
226         close(sockfd);
227         if(write_pos==response_buf){
228                 fprintf(stderr,"Empty response from HTTP server.\n");
229                 return -1;
230         }
231
232         // parse HTTP header
233         char* header_line = strtok(response_buf, "\r\n");
234         if(header_line==NULL){
235                 fprintf(stderr,"unparseable response from HTTP server.\n");
236                 return -1;
237         }
238         int ver1, ver2;
239
240         // extract http response code
241         sscanf (header_line, "HTTP/%d.%d %d %s", &ver1, &ver2, http_code, temp_buf);
242
243         return 0;
244 }