FAUST compiler  0.9.9.6b8
sourcefetcher.cpp
Go to the documentation of this file.
1 /*
2  * http_fetcher.c - HTTP handling functions
3  *
4  * HTTP Fetcher Copyright (C) 2001, 2003, 2004 Lyle Hanson
5  * (lhanson@users.sourceforge.net)
6  *
7  * This library is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Library General Public License as published by the
9  * Free Software Foundation; either version 2 of the License, or (at your
10  * option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15  * License for more details.
16  *
17  * See LICENSE file for details
18  *
19  * --------------------------------- Modified by Yann Orlarey, Grame to be used
20  * within Faust (2013/01/23)
21  *
22  */
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #ifndef WIN32
31 #include <strings.h>
32 #include <netdb.h>
33 #include <unistd.h>
34 #include <netinet/in.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #else
38 #include <winsock2.h>
39 #define close closesocket
40 #define write(s, buf, len) send(s, buf, (int)(len), 0)
41 #define read(s, buf, len) recv(s, buf, (int)(len), 0)
42 #define rindex strchr
43 #define herror perror
44 #endif
45 #include "compatibility.hh"
46 #include "sourcefetcher.hh"
47 
48 #define VERSION "0"
49 
50 /* Globals */
52 char *userAgent = NULL;
53 char *referer = NULL;
54 int hideUserAgent = 0;
55 int hideReferer = 1;
56 static int followRedirects = DEFAULT_REDIRECTS; /* # of redirects to
57  * follow */
58 extern const char *http_errlist[]; /* Array of HTTP Fetcher error
59  * messages */
60 extern char convertedError[128]; /* Buffer to used when errors contain
61  * %d */
62 static int errorSource = 0;
63 static int http_errno = 0;
64 static int errorInt = 0; /* When the error message has a %d in it,
65  * this variable is inserted */
66 
67 const char *http_errlist[] =
68 {
69  "Success", /* HF_SUCCESS */
70  "Internal Error. What the hell?!", /* HF_METAERROR */
71  "Got NULL url", /* HF_NULLURL */
72  "Timed out, no metadata for %d seconds", /* HF_HEADTIMEOUT */
73  "Timed out, no data for %d seconds", /* HF_DATATIMEOUT */
74  "Couldn't find return code in HTTP response", /* HF_FRETURNCODE */
75  "Couldn't convert return code in HTTP response", /* HF_CRETURNCODE */
76  "Request returned a status code of %d", /* HF_STATUSCODE */
77  "Couldn't convert Content-Length to integer", /* HF_CONTENTLEN */
78  "Network error (description unavailable)", /* HF_HERROR */
79  "Status code of %d but no Location: field", /* HF_CANTREDIRECT */
80  "Followed the maximum number of redirects (%d)" /* HF_MAXREDIRECTS */
81 };
82 
83 /*
84  * Used to copy in messages from http_errlist[] and replace %d's with the
85  * value of errorInt. Then we can pass the pointer to THIS
86  */
87 char convertedError[128];
88 
89 /*
90  * Actually downloads the page, registering a hit (donation) If the fileBuf
91  * passed in is NULL, the url is downloaded and then freed; otherwise the
92  * necessary space is allocated for fileBuf. Returns size of download on
93  * success, -1 on error is set,
94  */
95 int http_fetch(const char *url_tmp, char **fileBuf)
96 {
97  fd_set rfds;
98  struct timeval tv;
99  char headerBuf [HEADER_BUF_SIZE];
100  char *tmp, *url, *pageBuf, *requestBuf = NULL, *host, *charIndex;
101  int sock, bytesRead = 0, contentLength = -1, bufsize = REQUEST_BUF_SIZE;
102  int i, ret = -1, tempSize, selectRet, found = 0, /* For redirects */
103  redirectsFollowed = 0;
104 
105 
106  if (url_tmp == NULL) {
109  return -1;
110  }
111  /*
112  * Copy the url passed in into a buffer we can work with, change,
113  * etc.
114  */
115  url = (char *)malloc(strlen(url_tmp) + 1);
116  if (url == NULL) {
117  errorSource = ERRNO;
118  return -1;
119  }
120  strncpy(url, url_tmp, strlen(url_tmp) + 1);
121 
122  /*
123  * This loop allows us to follow redirects if need be. An
124  * afterthought, added to provide this basic functionality. Will
125  * hopefully be designed better in 2.x.x ;)
126  */
127  /*
128  * while(!found && (followRedirects < 0 || redirectsFollowed <
129  * followRedirects) )
130  */
131  do {
132  /* Seek to the file path portion of the url */
133  charIndex = strstr(url, "://");
134  if (charIndex != NULL) {
135  /* url contains a protocol field */
136  charIndex += strlen("://");
137  host = charIndex;
138  charIndex = strchr(charIndex, '/');
139  } else {
140  host = (char *)url;
141  charIndex = strchr(url, '/');
142  }
143 
144  /* Compose a request string */
145  requestBuf = (char *)malloc(bufsize);
146  if (requestBuf == NULL) {
147  free(url);
148  errorSource = ERRNO;
149  return -1;
150  }
151  requestBuf[0] = 0;
152 
153  if (charIndex == NULL) {
154  /*
155  * The url has no '/' in it, assume the user is
156  * making a root-level request
157  */
158  tempSize = (int)strlen("GET /") + (int)strlen(HTTP_VERSION) + 2;
159  if (_checkBufSize(&requestBuf, &bufsize, tempSize) ||
160  snprintf(requestBuf, bufsize, "GET / %s\r\n", HTTP_VERSION) < 0) {
161  free(url);
162  free(requestBuf);
163  errorSource = ERRNO;
164  return -1;
165  }
166  } else {
167  tempSize = (int)strlen("GET ") + (int)strlen(charIndex) +
168  (int)strlen(HTTP_VERSION) + 4;
169  /* + 4 is for ' ', '\r', '\n', and NULL */
170 
171  if (_checkBufSize(&requestBuf, &bufsize, tempSize) ||
172  snprintf(requestBuf, bufsize, "GET %s %s\r\n",
173  charIndex, HTTP_VERSION) < 0) {
174  free(url);
175  free(requestBuf);
176  errorSource = ERRNO;
177  return -1;
178  }
179  }
180 
181  /* Null out the end of the hostname if need be */
182  if (charIndex != NULL)
183  *charIndex = 0;
184 
185  /*
186  * Use Host: even though 1.0 doesn't specify it. Some
187  * servers won't play nice if we don't send Host, and it
188  * shouldn't hurt anything
189  */
190  ret = (int)bufsize - (int)strlen(requestBuf); /* Space left in buffer */
191  tempSize = (int)strlen("Host: ") + (int)strlen(host) + 3;
192  /* +3 for "\r\n\0" */
193  if (_checkBufSize(&requestBuf, &bufsize, tempSize + 128)) {
194  free(url);
195  free(requestBuf);
196  errorSource = ERRNO;
197  return -1;
198  }
199  strcat(requestBuf, "Host: ");
200  strcat(requestBuf, host);
201  strcat(requestBuf, "\r\n");
202 
203  if (!hideReferer && referer != NULL) { /* NO default referer */
204  tempSize = (int)strlen("Referer: ") + (int)strlen(referer) + 3;
205  /* + 3 is for '\r', '\n', and NULL */
206  if (_checkBufSize(&requestBuf, &bufsize, tempSize)) {
207  free(url);
208  free(requestBuf);
209  errorSource = ERRNO;
210  return -1;
211  }
212  strcat(requestBuf, "Referer: ");
213  strcat(requestBuf, referer);
214  strcat(requestBuf, "\r\n");
215  }
216  if (!hideUserAgent && userAgent == NULL) {
217  tempSize = (int)strlen("User-Agent: ") +
218  (int)strlen(DEFAULT_USER_AGENT) + (int)strlen(VERSION) + 4;
219  /* + 4 is for '\', '\r', '\n', and NULL */
220  if (_checkBufSize(&requestBuf, &bufsize, tempSize)) {
221  free(url);
222  free(requestBuf);
223  errorSource = ERRNO;
224  return -1;
225  }
226  strcat(requestBuf, "User-Agent: ");
227  strcat(requestBuf, DEFAULT_USER_AGENT);
228  strcat(requestBuf, "/");
229  strcat(requestBuf, VERSION);
230  strcat(requestBuf, "\r\n");
231  } else if (!hideUserAgent) {
232  tempSize = (int)strlen("User-Agent: ") + (int)strlen(userAgent) + 3;
233  /* + 3 is for '\r', '\n', and NULL */
234  if (_checkBufSize(&requestBuf, &bufsize, tempSize)) {
235  free(url);
236  free(requestBuf);
237  errorSource = ERRNO;
238  return -1;
239  }
240  strcat(requestBuf, "User-Agent: ");
241  strcat(requestBuf, userAgent);
242  strcat(requestBuf, "\r\n");
243  }
244  tempSize = (int)strlen("Connection: Close\r\n\r\n");
245  if (_checkBufSize(&requestBuf, &bufsize, tempSize)) {
246  free(url);
247  free(requestBuf);
248  errorSource = ERRNO;
249  return -1;
250  }
251  strcat(requestBuf, "Connection: Close\r\n\r\n");
252 
253  /* Now free any excess memory allocated to the buffer */
254  tmp = (char *)realloc(requestBuf, strlen(requestBuf) + 1);
255  if (tmp == NULL) {
256  free(url);
257  free(requestBuf);
258  errorSource = ERRNO;
259  return -1;
260  }
261  requestBuf = tmp;
262 
263  sock = makeSocket(host); /* errorSource set within
264  * makeSocket */
265  if (sock == -1) {
266  free(url);
267  free(requestBuf);
268  return -1;
269  }
270  free(url);
271  url = NULL;
272 
273  if (write(sock, requestBuf, strlen(requestBuf)) == -1) {
274  close(sock);
275  free(requestBuf);
276  errorSource = ERRNO;
277  return -1;
278  }
279  free(requestBuf);
280  requestBuf = NULL;
281 
282  /* Grab enough of the response to get the metadata */
283  ret = _http_read_header(sock, headerBuf); /* errorSource set
284  * within */
285  if (ret < 0) {
286  close(sock);
287  return -1;
288  }
289  /* Get the return code */
290  charIndex = strstr(headerBuf, "HTTP/");
291  if (charIndex == NULL) {
292  close(sock);
295  return -1;
296  }
297  while (*charIndex != ' ')
298  charIndex++;
299  charIndex++;
300 
301  ret = sscanf(charIndex, "%d", &i);
302  if (ret != 1) {
303  close(sock);
306  return -1;
307  }
308  if (i < 200 || i > 307) {
309  close(sock);
310  errorInt = i; /* Status code, to be inserted in
311  * error string */
314  return -1;
315  }
316  /*
317  * If a redirect, repeat operation until final URL is found
318  * or we redirect followRedirects times. Note the case
319  * sensitive "Location", should probably be made more robust
320  * in the future (without relying on the non-standard
321  * strcasecmp()). This bit mostly by Dean Wilder, tweaked by
322  * me
323  */
324  if (i >= 300) {
325  redirectsFollowed++;
326 
327  /*
328  * Pick up redirect URL, allocate new url, and repeat
329  * process
330  */
331  charIndex = strstr(headerBuf, "Location:");
332  if (!charIndex) {
333  close(sock);
334  errorInt = i; /* Status code, to be
335  * inserted in error string */
338  return -1;
339  }
340  charIndex += strlen("Location:");
341  /* Skip any whitespace... */
342  while (*charIndex != '\0' && isspace(*charIndex))
343  charIndex++;
344  if (*charIndex == '\0') {
345  close(sock);
346  errorInt = i; /* Status code, to be
347  * inserted in error string */
350  return -1;
351  }
352  i = (int)strcspn(charIndex, " \r\n");
353  if (i > 0) {
354  url = (char *)malloc(i + 1);
355  strncpy(url, charIndex, i);
356  url[i] = '\0';
357  } else
358  /*
359  * Found 'Location:' but contains no URL!
360  * We'll handle it as 'found', hopefully the
361  * resulting document will give the user a
362  * hint as to what happened.
363  */
364  found = 1;
365  } else {
366  found = 1;
367  }
368  } while (!found && (followRedirects < 0 || redirectsFollowed <= followRedirects));
369 
370  if (url) { /* Redirection code may malloc this, then
371  * exceed followRedirects */
372  free(url);
373  url = NULL;
374  }
375  if (redirectsFollowed >= followRedirects && !found) {
376  close(sock);
377  errorInt = followRedirects; /* To be inserted in error
378  * string */
381  return -1;
382  }
383  /*
384  * Parse out about how big the data segment is. Note that under
385  * current HTTP standards (1.1 and prior), the Content-Length field
386  * is not guaranteed to be accurate or even present. I just use it
387  * here so I can allocate a ballpark amount of memory.
388  *
389  * Note that some servers use different capitalization
390  */
391  charIndex = strstr(headerBuf, "Content-Length:");
392  if (charIndex == NULL)
393  charIndex = strstr(headerBuf, "Content-length:");
394 
395  if (charIndex != NULL) {
396  ret = sscanf(charIndex + strlen("content-length: "), "%d",
397  &contentLength);
398  if (ret < 1) {
399  close(sock);
402  return -1;
403  }
404  }
405  /* Allocate enough memory to hold the page */
406  if (contentLength == -1)
407  contentLength = DEFAULT_PAGE_BUF_SIZE;
408 
409  pageBuf = (char *)malloc(contentLength);
410  if (pageBuf == NULL) {
411  close(sock);
412  errorSource = ERRNO;
413  return -1;
414  }
415  /* Begin reading the body of the file */
416  while (ret > 0) {
417  FD_ZERO(&rfds);
418  FD_SET(sock, &rfds);
419  tv.tv_sec = timeout;
420  tv.tv_usec = 0;
421 
422  if (timeout >= 0)
423  selectRet = select(sock + 1, &rfds, NULL, NULL, &tv);
424  else /* No timeout, can block indefinately */
425  selectRet = select(sock + 1, &rfds, NULL, NULL, NULL);
426 
427  if (selectRet == 0) {
430  errorInt = timeout;
431  close(sock);
432  free(pageBuf);
433  return -1;
434  } else if (selectRet == -1) {
435  close(sock);
436  free(pageBuf);
437  errorSource = ERRNO;
438  return -1;
439  }
440  ret = read(sock, pageBuf + bytesRead, contentLength);
441  if (ret == -1) {
442  close(sock);
443  free(pageBuf);
444  errorSource = ERRNO;
445  return -1;
446  }
447  bytesRead += ret;
448 
449  if (ret > 0) {
450  /*
451  * To be tolerant of inaccurate Content-Length
452  * fields, we'll allocate another read-sized chunk to
453  * make sure we have enough room.
454  */
455  tmp = (char *)realloc(pageBuf, bytesRead + contentLength);
456  if (tmp == NULL) {
457  close(sock);
458  free(pageBuf);
459  errorSource = ERRNO;
460  return -1;
461  }
462  pageBuf = tmp;
463  }
464  }
465 
466  /*
467  * The download buffer is too large. Trim off the safety padding.
468  * Note that we add one NULL byte to the end of the data, as it may
469  * not already be NULL terminated and we can't be sure what type of
470  * data it is or what the caller will do with it.
471  */
472  tmp = (char *)realloc(pageBuf, bytesRead + 1);
473  /*
474  * tmp shouldn't be null, since we're _shrinking_ the buffer, and if
475  * it DID fail, we could go on with the too-large buffer, but
476  * something would DEFINATELY be wrong, so we'll just give an error
477  * message
478  */
479  if (tmp == NULL) {
480  close(sock);
481  free(pageBuf);
482  errorSource = ERRNO;
483  return -1;
484  }
485  pageBuf = tmp;
486  pageBuf[bytesRead] = '\0'; /* NULL terminate the data */
487 
488  if (fileBuf == NULL) /* They just wanted us to "hit" the url */
489  free(pageBuf);
490  else
491  *fileBuf = pageBuf;
492 
493  close(sock);
494  return bytesRead;
495 }
496 
497 
498 
499 /*
500  * Changes the User Agent. Returns 0 on success, -1 on error.
501  */
502 int http_setUserAgent(const char *newAgent)
503 {
504  static int freeOldAgent = 0; /* Indicates previous
505  * malloc's */
506  char *tmp;
507 
508  if (newAgent == NULL) {
509  if (freeOldAgent)
510  free(userAgent);
511  userAgent = NULL;
512  hideUserAgent = 1;
513  } else {
514  tmp = (char *)malloc(strlen(newAgent));
515  if (tmp == NULL) {
516  errorSource = ERRNO;
517  return -1;
518  }
519  if (freeOldAgent)
520  free(userAgent);
521  userAgent = tmp;
522  strcpy(userAgent, newAgent);
523  freeOldAgent = 1;
524  hideUserAgent = 0;
525  }
526 
527  return 0;
528 }
529 
530 
531 
532 /*
533  * Changes the Referer. Returns 0 on success, -1 on error
534  */
535 int http_setReferer(const char *newReferer)
536 {
537  static int freeOldReferer = 0; /* Indicated previous
538  * malloc's */
539  char *tmp;
540 
541  if (newReferer == NULL) {
542  if (freeOldReferer)
543  free(referer);
544  referer = NULL;
545  hideReferer = 1;
546  } else {
547  tmp = (char *)malloc(strlen(newReferer));
548  if (tmp == NULL) {
549  errorSource = ERRNO;
550  return -1;
551  }
552  if (freeOldReferer)
553  free(referer);
554  referer = tmp;
555  strcpy(referer, newReferer);
556  freeOldReferer = 1;
557  hideReferer = 0;
558  }
559 
560  return 0;
561 }
562 
563 
564 
565 /*
566  * Changes the amount of time that HTTP Fetcher will wait for data before
567  * timing out on reads
568  */
569 void http_setTimeout(int seconds)
570 {
571  timeout = seconds;
572 }
573 
574 
575 
576 /*
577  * Changes the number of HTTP redirects HTTP Fetcher will automatically
578  * follow. If a request returns a status code of 3XX and contains a
579  * "Location:" field, the library will transparently follow up to the
580  * specified number of redirects. With this implementation (which is just a
581  * stopgap, really) the caller won't be aware of any redirection and will
582  * assume the returned document came from the original URL. To disable
583  * redirects, pass a 0. To follow unlimited redirects (probably unwise),
584  * pass a negative value. The default is to follow 3 redirects.
585  */
586 void http_setRedirects(int redirects)
587 {
588  followRedirects = redirects;
589 }
590 
591 
592 
593 /*
594  * Puts the filename portion of the url into 'filename'. Returns: 0 on
595  * success 1 when url contains no end filename (i.e., 'www.foo.com/'), and
596  * **filename should not be assumed to be valid -1 on error
597  */
598 int http_parseFilename(const char *url, char **filename)
599 {
600  char *ptr;
601 
602  if (url == NULL) {
605  return -1;
606  }
607  ptr = (char *)rindex(url, '/');
608  if (ptr == NULL)
609  /* Root level request, apparently */
610  return 1;
611 
612  ptr++;
613  if (*ptr == '\0')
614  return 1;
615 
616  *filename = (char *)malloc(strlen(ptr));
617  if (*filename == NULL) {
618  errorSource = ERRNO;
619  return -1;
620  }
621  strcpy(*filename, ptr);
622 
623  return 0;
624 }
625 
626 
627 
628 /*
629  * Depending on the source of error, calls either perror() or prints an HTTP
630  * Fetcher error message to stdout
631  */
632 void http_perror(const char *string)
633 {
634  if (errorSource == ERRNO)
635  perror(string);
636  else if (errorSource == H_ERRNO)
637  herror(string);
638  else if (errorSource == FETCHER_ERROR) {
639  const char *stringIndex;
640 
641  if (strstr(http_errlist[http_errno], "%d") == NULL) {
642  fputs(string, stderr);
643  fputs(": ", stderr);
644  fputs(http_errlist[http_errno], stderr);
645  fputs("\n", stderr);
646  } else {
647  /*
648  * The error string has a %d in it, we need to insert
649  * errorInt
650  */
651  stringIndex = http_errlist[http_errno];
652  while (*stringIndex != '%') { /* Print up to the %d */
653  fputc(*stringIndex, stderr);
654  stringIndex++;
655  }
656  fprintf(stderr, "%d", errorInt); /* Print the number */
657  stringIndex += 2; /* Skip past the %d */
658  while (*stringIndex != 0) { /* Print up to the end
659  * NULL */
660  fputc(*stringIndex, stderr);
661  stringIndex++;
662  }
663  fputs("\n", stderr);
664  }
665  }
666 }
667 
668 
669 
670 /*
671  * Returns a pointer to the current error description message. The message
672  * pointed to is only good until the next call to http_strerror(), so if you
673  * need to hold on to the message for a while you should make a copy of it
674  */
675 const char* http_strerror()
676 {
677  extern int errno;
678 
679  if (errorSource == ERRNO)
680  return strerror(errno);
681  else if (errorSource == H_ERRNO)
682 #ifdef HAVE_HSTRERROR
683  return hstrerror(h_errno);
684 #else
685  return http_errlist[HF_HERROR];
686 #endif
687  else if (errorSource == FETCHER_ERROR) {
688  if (strstr(http_errlist[http_errno], "%d") == NULL)
689  return http_errlist[http_errno];
690  else {
691  /*
692  * The error string has a %d in it, we need to insert
693  * errorInt. convertedError[128] has been declared
694  * for that purpose
695  */
696  char *stringIndex, *originalError;
697 
698  originalError = (char *)http_errlist[http_errno];
699  convertedError[0] = 0; /* Start off with NULL */
700  stringIndex = strstr(originalError, "%d");
701  strncat(convertedError, originalError, /* Copy up to %d */
702  abs(stringIndex - originalError));
703  sprintf(&convertedError[strlen(convertedError)], "%d", errorInt);
704  stringIndex += 2; /* Skip past the %d */
705  strcat(convertedError, stringIndex);
706 
707  return convertedError;
708  }
709  }
710  return http_errlist[HF_METAERROR]; /* Should NEVER happen */
711 }
712 
713 
714 /*
715  * Reads the metadata of an HTTP response. Perhaps a little inefficient, as
716  * it reads 1 byte at a time, but I don't think it's that much of a loss
717  * (most headers aren't HUGE). Returns: # of bytes read on success, or -1 on
718  * error
719  */
720 int _http_read_header(int sock, char *headerPtr)
721 {
722  fd_set rfds;
723  struct timeval tv;
724  int bytesRead = 0, newlines = 0, ret, selectRet;
725 
726  while (newlines != 2 && bytesRead != HEADER_BUF_SIZE) {
727  FD_ZERO(&rfds);
728  FD_SET(sock, &rfds);
729  tv.tv_sec = timeout;
730  tv.tv_usec = 0;
731 
732  if (timeout >= 0)
733  selectRet = select(sock + 1, &rfds, NULL, NULL, &tv);
734  else /* No timeout, can block indefinately */
735  selectRet = select(sock + 1, &rfds, NULL, NULL, NULL);
736 
737  if (selectRet == 0) {
740  errorInt = timeout;
741  return -1;
742  } else if (selectRet == -1) {
743  errorSource = ERRNO;
744  return -1;
745  }
746  ret = read(sock, headerPtr, 1);
747  if (ret == -1) {
748  errorSource = ERRNO;
749  return -1;
750  }
751  bytesRead++;
752 
753  if (*headerPtr == '\r') { /* Ignore CR */
754  /*
755  * Basically do nothing special, just don't set
756  * newlines to 0
757  */
758  headerPtr++;
759  continue;
760  } else if (*headerPtr == '\n') /* LF is the separator */
761  newlines++;
762  else
763  newlines = 0;
764 
765  headerPtr++;
766  }
767 
768  headerPtr -= 3; /* Snip the trailing LF's */
769  *headerPtr = '\0';
770  return bytesRead;
771 }
772 
773 
774 
775 /*
776  * Opens a TCP socket and returns the descriptor Returns: socket descriptor,
777  * or -1 on error
778  */
779 int makeSocket(char *host)
780 {
781  int sock; /* Socket descriptor */
782  struct sockaddr_in sa; /* Socket address */
783  struct hostent *hp; /* Host entity */
784  int ret;
785  int port;
786  char *p;
787 
788  /* Check for port number specified in URL */
789  p = strchr(host, ':');
790  if (p) {
791  port = atoi(p + 1);
792  *p = '\0';
793  } else
794  port = PORT_NUMBER;
795 
796  hp = gethostbyname(host);
797  if (hp == NULL) {
799  return -1;
800  }
801  /* Copy host address from hostent to (server) socket address */
802  memcpy((char *)&sa.sin_addr, (char *)hp->h_addr, hp->h_length);
803  sa.sin_family = hp->h_addrtype; /* Set service sin_family to PF_INET */
804  sa.sin_port = htons(port); /* Put portnum into sockaddr */
805 
806  sock = (int)socket(hp->h_addrtype, SOCK_STREAM, 0);
807  if (sock == -1) {
808  errorSource = ERRNO;
809  return -1;
810  }
811  ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
812  if (ret == -1) {
813  errorSource = ERRNO;
814  return -1;
815  }
816  return sock;
817 }
818 
819 
820 
821 /*
822  * Determines if the given NULL-terminated buffer is large enough to
823  * concatenate the given number of characters. If not, it attempts to grow
824  * the buffer to fit. Returns: 0 on success, or -1 on error (original buffer
825  * is unchanged).
826  */
827 int _checkBufSize(char **buf, int *bufsize, int more)
828 {
829  char *tmp;
830  int roomLeft = (int)*bufsize - (int)(strlen(*buf) + 1);
831  if (roomLeft > more)
832  return 0;
833  tmp = (char *)realloc(*buf, *bufsize + more + 1);
834  if (tmp == NULL)
835  return -1;
836  *buf = tmp;
837  *bufsize += more + 1;
838  return 0;
839 }
#define FETCHER_ERROR
#define HF_CONTENTLEN
void http_setRedirects(int redirects)
static int errorInt
char * referer
void http_perror(const char *string)
#define REQUEST_BUF_SIZE
#define HF_FRETURNCODE
#define DEFAULT_PAGE_BUF_SIZE
char convertedError[128]
interval abs(const interval &x)
Definition: interval.hh:226
const char * http_strerror()
const char * http_errlist[]
#define HF_MAXREDIRECTS
int _http_read_header(int sock, char *headerPtr)
char * userAgent
static int errorSource
int http_setUserAgent(const char *newAgent)
void http_setTimeout(int seconds)
#define HTTP_VERSION
int makeSocket(char *host)
#define DEFAULT_REDIRECTS
static int followRedirects
#define HF_NULLURL
int http_parseFilename(const char *url, char **filename)
#define HF_CRETURNCODE
#define HF_HERROR
#define HF_METAERROR
#define VERSION
#define DEFAULT_READ_TIMEOUT
#define ERRNO
#define HF_CANTREDIRECT
int http_fetch(const char *url_tmp, char **fileBuf)
#define HF_DATATIMEOUT
int timeout
#define HF_HEADTIMEOUT
int http_setReferer(const char *newReferer)
#define PORT_NUMBER
#define HF_STATUSCODE
#define DEFAULT_USER_AGENT
int _checkBufSize(char **buf, int *bufsize, int more)
int hideReferer
int hideUserAgent
#define H_ERRNO
#define HEADER_BUF_SIZE
static int http_errno