Rizin
unix-like reverse engineering framework and cli tools
socket_http.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2020 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_socket.h>
5 #include <rz_util.h>
6 
7 #if __WINDOWS__
8 #include <WinInet.h>
9 #endif
10 
11 #define SOCKET_HTTP_MAX_HEADER_LENGTH 0x2000
12 #define SOCKET_HTTP_MAX_REDIRECTS 5
13 
14 static size_t socket_slurp(RzSocket *s, RzBuffer *buf) {
15  size_t i;
16  if (rz_socket_ready(s, 1, 0) != 1) {
17  return 0;
18  }
19  rz_socket_block_time(s, true, 0, 1000);
20  for (i = 0; i < SOCKET_HTTP_MAX_HEADER_LENGTH; i += 1) {
21  ut8 c;
22  int olen = rz_socket_read_block(s, &c, 1);
23  if (olen != 1) {
24  rz_buf_append_bytes(buf, (ut8 *)"", 1);
25  break;
26  }
28  }
29  return i;
30 }
31 
32 static char *socket_http_get_recursive(const char *url, int *code, int *rlen, ut32 redirections);
33 
34 static char *socket_http_answer(RzSocket *s, int *code, int *rlen, ut32 redirections) {
36  const char *p;
37  int ret, len = 0, delta = 0;
38  char *dn = NULL;
40  if (!b) {
41  return NULL;
42  }
43  char *res = NULL;
44  size_t olen = socket_slurp(s, b);
45  char *buf = malloc(olen + 1);
46  if (!buf) {
47  goto exit;
48  }
49  rz_buf_read_at(b, 0, (ut8 *)buf, olen);
50  buf[olen] = 0;
51  char *dnn = (char *)rz_str_casestr(buf, "\n\n");
52  char *drn = (char *)rz_str_casestr(buf, "\r\n\r\n");
53  if (dnn) {
54  if (drn && (drn < dnn)) {
55  dn = drn;
56  delta = 4;
57  } else {
58  dn = dnn;
59  delta = 2;
60  }
61  } else {
62  dn = drn;
63  delta = 4;
64  }
65  if (!dn) {
66  goto exit;
67  }
68 
69  olen -= delta;
70  *dn = 0; // chop headers
71 
72  /* Follow redirects */
73  p = rz_str_casestr(buf, "Location:");
74  if (p) {
75  if (!redirections) {
76  eprintf("Too many redirects\n");
77  goto exit;
78  }
79  p += strlen("Location:");
80  char *end_url = strchr(p, '\n');
81  if (end_url) {
82  int url_len = end_url - p;
83  char *url = rz_str_ndup(p, url_len);
85  res = socket_http_get_recursive(url, code, rlen, --redirections);
86  free(url);
87  len = *rlen;
88  }
89  goto exit;
90  }
91 
92  /* Parse Len */
93  p = rz_str_casestr(buf, "Content-Length: ");
94  if (p) {
95  len = atoi(p + 16);
96  } else {
97  len = olen - (dn - buf);
98  }
99  if (len > 0) {
100  if (len > olen) {
101  res = malloc(len + 2);
102  if (!res) {
103  goto exit;
104  }
105  olen -= dn - buf;
106  memcpy(res, dn + delta, olen);
107  do {
108  ret = rz_socket_read_block(s, (ut8 *)res + olen, len - olen);
109  if (ret < 1) {
110  break;
111  }
112  olen += ret;
113  } while (olen < len);
114  res[len] = 0;
115  } else {
116  res = malloc(len + 1);
117  if (res) {
118  memcpy(res, dn + delta, len);
119  res[len] = 0;
120  }
121  }
122  } else {
123  res = strdup("");
124  }
125 exit:
126  free(buf);
127  rz_buf_free(b);
129  if (rlen) {
130  *rlen = len;
131  }
132  return res;
133 }
134 
135 #if __WINDOWS__
136 static char *http_get_w32(const char *url, int *code, int *rlen) {
137  HINTERNET hInternet = InternetOpenA("rizin " RZ_VERSION, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
138  if (!hInternet) {
139  rz_sys_perror("InternetOpenA");
140  return NULL;
141  }
142  HINTERNET hOpenUrl = InternetOpenUrlA(hInternet, url, NULL, 0, 0, 0);
143  if (!hOpenUrl) {
144  rz_sys_perror("InternetOpenUrlA");
145  InternetCloseHandle(hInternet);
146  return NULL;
147  }
148 
149  char *ret = NULL;
150  size_t read_sz = 0x100000;
151  DWORD r = 0, w = 0;
152  bool res = true;
153  do {
154  w += r;
155  if (!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
156  read_sz *= 2;
157  }
158  char *tmp = realloc(ret, read_sz + w);
159  if (!tmp) {
160  RZ_FREE(ret);
161  goto exit;
162  }
163  ret = tmp;
164  } while (!(res = InternetReadFile(hOpenUrl, ret + w, read_sz, &r)) || r);
165 
166  if (res) {
167  char *tmp = realloc(ret, (size_t)w + 1);
168  if (tmp) {
169  ret = tmp;
170  ret[w] = 0;
171  } else {
172  RZ_FREE(ret);
173  }
174  } else {
175  RZ_FREE(ret);
176  }
177 
178 exit:
179  if (rlen) {
180  *rlen = w;
181  }
182  if (code && w) {
183  *code = 200;
184  }
185  InternetCloseHandle(hInternet);
186  InternetCloseHandle(hOpenUrl);
187  return ret;
188 }
189 #endif
190 
191 static char *socket_http_get_recursive(const char *url, int *code, int *rlen, ut32 redirections) {
192  if (code) {
193  *code = 0;
194  }
195  if (rlen) {
196  *rlen = 0;
197  }
198  char *curl_env = rz_sys_getenv("RZ_CURL");
199  if (!RZ_STR_ISEMPTY(curl_env) && atoi(curl_env)) {
200  int len;
201  char *escaped_url = rz_str_escape_sh(url);
202  char *command = rz_str_newf("curl -sfL -o - \"%s\"", escaped_url);
203  char *res = rz_sys_cmd_str(command, NULL, &len);
204  free(escaped_url);
205  free(command);
206  free(curl_env);
207  if (!res) {
208  return NULL;
209  }
210  if (res) {
211  if (code) {
212  *code = 200;
213  }
214  if (rlen) {
215  *rlen = len;
216  }
217  }
218  return res;
219  }
220  free(curl_env);
221 #if __WINDOWS__
222  return http_get_w32(url, code, rlen);
223 #else
224  RzSocket *s;
225  bool ssl = rz_str_startswith(url, "https://");
226 #if !HAVE_LIB_SSL
227  if (ssl) {
228  eprintf("Tried to get '%s', but SSL support is disabled, set RZ_CURL=1 to use curl\n", url);
229  return NULL;
230  }
231 #endif
232  char *response, *host, *path, *port = "80";
233  char *uri = strdup(url);
234  if (!uri) {
235  return NULL;
236  }
237  host = strstr(uri, "://");
238  if (!host) {
239  free(uri);
240  eprintf("rz_socket_http_get: Invalid URI");
241  return NULL;
242  }
243  host += 3;
244  port = strchr(host, ':');
245  if (!port) {
246 #if HAVE_LIB_SSL
247  port = ssl ? "443" : "80";
248 #else
249  port = "80";
250 #endif
251  path = host;
252  } else {
253  *port++ = 0;
254  path = port;
255  }
256  path = strchr(path, '/');
257  if (!path) {
258  path = "";
259  } else {
260  *path++ = 0;
261  }
262  s = rz_socket_new(ssl);
263  if (!s) {
264  eprintf("rz_socket_http_get: Cannot create socket\n");
265  free(uri);
266  return NULL;
267  }
268  if (rz_socket_connect_tcp(s, host, port, 0)) {
270  "GET /%s HTTP/1.1\r\n"
271  "User-Agent: rizin " RZ_VERSION "\r\n"
272  "Accept: */*\r\n"
273  "Host: %s:%s\r\n"
274  "\r\n",
275  path, host, port);
276  response = socket_http_answer(s, code, rlen, redirections);
277  } else {
278  eprintf("Cannot connect to %s:%s\n", host, port);
279  response = NULL;
280  }
281  free(uri);
282  rz_socket_free(s);
283  return response;
284 #endif
285 }
286 
287 RZ_API char *rz_socket_http_get(const char *url, int *code, int *rlen) {
289 }
290 
291 RZ_API char *rz_socket_http_post(const char *url, const char *data, int *code, int *rlen) {
292  RzSocket *s;
293  bool ssl = rz_str_startswith(url, "https://");
294  char *uri = strdup(url);
295  if (!uri) {
296  return NULL;
297  }
298 
299  char *host = strstr(uri, "://");
300  if (!host) {
301  free(uri);
302  printf("Invalid URI");
303  return NULL;
304  }
305  host += 3;
306  char *port = strchr(host, ':');
307  if (!port) {
308  port = (ssl) ? "443" : "80";
309  } else {
310  *port++ = 0;
311  }
312  char *path = strchr(host, '/');
313  if (!path) {
314  path = "";
315  } else {
316  *path++ = 0;
317  }
318  s = rz_socket_new(ssl);
319  if (!s) {
320  printf("Cannot create socket\n");
321  free(uri);
322  return NULL;
323  }
324  if (!rz_socket_connect_tcp(s, host, port, 0)) {
325  eprintf("Cannot connect to %s:%s\n", host, port);
326  free(uri);
327  return NULL;
328  }
329  /* Send */
331  "POST /%s HTTP/1.0\r\n"
332  "User-Agent: rizin " RZ_VERSION "\r\n"
333  "Accept: */*\r\n"
334  "Host: %s\r\n"
335  "Content-Length: %i\r\n"
336  "Content-Type: application/x-www-form-urlencoded\r\n"
337  "\r\n",
338  path, host, (int)strlen(data));
339  free(uri);
340  rz_socket_write(s, (void *)data, strlen(data));
341  return socket_http_answer(s, code, rlen, 0);
342 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
#define w
Definition: crypto_rc6.c:13
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
uint32_t ut32
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
url
Definition: setup.py:262
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API bool rz_buf_append_bytes(RZ_NONNULL RzBuffer *b, RZ_NONNULL const ut8 *buf, ut64 len)
Append an array of bytes to the buffer.
Definition: buf.c:732
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_bytes(RZ_NULLABLE RZ_BORROW const ut8 *bytes, ut64 len)
Creates a new buffer with a bytes array.
Definition: buf.c:465
RZ_API int rz_socket_close(RzSocket *s)
Definition: socket.c:419
RZ_API int rz_socket_read_block(RzSocket *s, unsigned char *buf, int len)
Definition: socket.c:808
RZ_API int rz_socket_ready(RzSocket *s, int secs, int usecs)
Definition: socket.c:688
#define rz_socket_connect_tcp(a, b, c, d)
Definition: rz_socket.h:99
RZ_API bool rz_socket_block_time(RzSocket *s, bool block, int sec, int usec)
Definition: socket.c:649
RZ_API void rz_socket_printf(RzSocket *s, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API RzSocket * rz_socket_new(bool is_ssl)
Definition: socket.c:179
RZ_API int rz_socket_free(RzSocket *s)
Definition: socket.c:453
RZ_API int rz_socket_write(RzSocket *s, void *buf, int len)
Definition: socket.c:724
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
Definition: str_trim.c:190
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API const char * rz_str_casestr(const char *a, const char *b)
Definition: str.c:2757
RZ_API char * rz_str_escape_sh(const char *buf)
Definition: str.c:1560
RZ_API char * rz_sys_getenv(const char *key)
Get the value of an environment variable named key or NULL if none exists.
Definition: sys.c:483
RZ_API int RZ_API char * rz_sys_cmd_str(const char *cmd, const char *input, int *len)
Definition: sys.c:669
#define rz_sys_perror(x)
Definition: rz_types.h:336
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_VERSION
Definition: rz_version.h:8
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
#define SOCKET_HTTP_MAX_REDIRECTS
Definition: socket_http.c:12
static char * socket_http_answer(RzSocket *s, int *code, int *rlen, ut32 redirections)
Definition: socket_http.c:34
static char * socket_http_get_recursive(const char *url, int *code, int *rlen, ut32 redirections)
Definition: socket_http.c:191
static size_t socket_slurp(RzSocket *s, RzBuffer *buf)
Definition: socket_http.c:14
#define SOCKET_HTTP_MAX_HEADER_LENGTH
Definition: socket_http.c:11
RZ_API char * rz_socket_http_get(const char *url, int *code, int *rlen)
Definition: socket_http.c:287
RZ_API char * rz_socket_http_post(const char *url, const char *data, int *code, int *rlen)
Definition: socket_http.c:291
Definition: inftree9.h:24
const char * command
Definition: main.c:7
static st64 delta
Definition: vmenus.c:2425
DWORD