http_lib.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * Http put/get mini lib
  3. * written by L. Demailly
  4. * (c) 1998 Laurent Demailly - http://www.demailly.com/~dl/
  5. * (c) 1996 Observatoire de Paris - Meudon - France
  6. * see LICENSE for terms, conditions and DISCLAIMER OF ALL WARRANTIES
  7. *
  8. * $Id: http_lib.c,v 3.5 1998/09/23 06:19:15 dl Exp $
  9. *
  10. * Description : Use http protocol, connects to server to echange data
  11. *
  12. * $Log: http_lib.c,v $
  13. * Revision 3.5 1998/09/23 06:19:15 dl
  14. * portability and http 1.x (1.1 and later) compatibility
  15. *
  16. * Revision 3.4 1998/09/23 05:44:27 dl
  17. * added support for HTTP/1.x answers
  18. *
  19. * Revision 3.3 1996/04/25 19:07:22 dl
  20. * using intermediate variable for htons (port) so it does not yell
  21. * on freebsd (thx pp for report)
  22. *
  23. * Revision 3.2 1996/04/24 13:56:08 dl
  24. * added proxy support through http_proxy_server & http_proxy_port
  25. * some httpd *needs* cr+lf so provide them
  26. * simplification + cleanup
  27. *
  28. * Revision 3.1 1996/04/18 13:53:13 dl
  29. * http-tiny release 1.0
  30. *
  31. *
  32. */
  33. static char *rcsid="$Id: http_lib.c,v 3.5 1998/09/23 06:19:15 dl Exp $";
  34. #define VERBOSE
  35. /* http_lib - Http data exchanges mini library.
  36. */
  37. #ifndef OSK
  38. /* unix */
  39. #include <sys/types.h>
  40. #include <sys/socket.h>
  41. #include <netinet/in.h>
  42. #include <arpa/inet.h>
  43. #include <netdb.h>
  44. #include <ctype.h>
  45. #include <string.h>
  46. #include <unistd.h>
  47. #include <stdlib.h>
  48. static int http_read_line (int fd,char *buffer, int max) ;
  49. static int http_read_buffer (int fd,char *buffer, int max) ;
  50. #else
  51. /* OS/9 includes */
  52. #include <modes.h>
  53. #include <types.h>
  54. #include <machine/reg.h>
  55. #include <INET/socket.h>
  56. #include <INET/in.h>
  57. #include <INET/netdb.h>
  58. #include <INET/pwd.h>
  59. extern char *malloc();
  60. #endif /* OS9/Unix */
  61. #include <stdio.h>
  62. #include "http_lib.h"
  63. #define SERVER_DEFAULT "adonis"
  64. /* pointer to a mallocated string containing server name or NULL */
  65. char *http_server=NULL ;
  66. /* server port number */
  67. int http_port=5757;
  68. /* pointer to proxy server name or NULL */
  69. char *http_proxy_server=NULL;
  70. /* proxy server port number or 0 */
  71. int http_proxy_port=0;
  72. /* user agent id string */
  73. static char *http_user_agent="adlib/3 ($Date: 1998/09/23 06:19:15 $)";
  74. /*
  75. * read a line from file descriptor
  76. * returns the number of bytes read. negative if a read error occured
  77. * before the end of line or the max.
  78. * cariage returns (CR) are ignored.
  79. */
  80. static int http_read_line (fd,buffer,max)
  81. int fd; /* file descriptor to read from */
  82. char *buffer; /* placeholder for data */
  83. int max; /* max number of bytes to read */
  84. { /* not efficient on long lines (multiple unbuffered 1 char reads) */
  85. int n=0;
  86. while (n<max) {
  87. if (read(fd,buffer,1)!=1) {
  88. n= -n;
  89. break;
  90. }
  91. n++;
  92. if (*buffer=='\015') continue; /* ignore CR */
  93. if (*buffer=='\012') break; /* LF is the separator */
  94. buffer++;
  95. }
  96. *buffer=0;
  97. return n;
  98. }
  99. /*
  100. * read data from file descriptor
  101. * retries reading until the number of bytes requested is read.
  102. * returns the number of bytes read. negative if a read error (EOF) occured
  103. * before the requested length.
  104. */
  105. static int http_read_buffer (fd,buffer,length)
  106. int fd; /* file descriptor to read from */
  107. char *buffer; /* placeholder for data */
  108. int length; /* number of bytes to read */
  109. {
  110. int n,r;
  111. for (n=0; n<length; n+=r) {
  112. r=read(fd,buffer,length-n);
  113. if (r<=0) return -n;
  114. buffer+=r;
  115. }
  116. return n;
  117. }
  118. typedef enum
  119. {
  120. CLOSE, /* Close the socket after the query (for put) */
  121. KEEP_OPEN /* Keep it open */
  122. } querymode;
  123. #ifndef OSK
  124. static http_retcode http_query(char *command, char *url,
  125. char *additional_header, querymode mode,
  126. char* data, int length, int *pfd);
  127. #endif
  128. /* beware that filename+type+rest of header must not exceed MAXBUF */
  129. /* so we limit filename to 256 and type to 64 chars in put & get */
  130. #define MAXBUF 512
  131. /*
  132. * Pseudo general http query
  133. *
  134. * send a command and additional headers to the http server.
  135. * optionally through the proxy (if http_proxy_server and http_proxy_port are
  136. * set).
  137. *
  138. * Limitations: the url is truncated to first 256 chars and
  139. * the server name to 128 in case of proxy request.
  140. */
  141. static http_retcode http_query(command, url, additional_header, mode,
  142. data, length, pfd)
  143. char *command; /* command to send */
  144. char *url; /* url / filename queried */
  145. char *additional_header; /* additional header */
  146. querymode mode; /* type of query */
  147. char *data; /* Data to send after header. If NULL, not data is sent */
  148. int length; /* size of data */
  149. int *pfd; /* pointer to variable where to set file descriptor value */
  150. {
  151. int s;
  152. struct hostent *hp;
  153. struct sockaddr_in server;
  154. char header[MAXBUF];
  155. int hlg;
  156. http_retcode ret;
  157. int proxy=(http_proxy_server!=NULL && http_proxy_port!=0);
  158. int port = proxy ? http_proxy_port : http_port ;
  159. if (pfd) *pfd=-1;
  160. /* get host info by name :*/
  161. if ((hp = gethostbyname( proxy ? http_proxy_server
  162. : ( http_server ? http_server
  163. : SERVER_DEFAULT )
  164. ))) {
  165. memset((char *) &server,0, sizeof(server));
  166. memmove((char *) &server.sin_addr, hp->h_addr, hp->h_length);
  167. server.sin_family = hp->h_addrtype;
  168. server.sin_port = (unsigned short) htons( port );
  169. } else
  170. return ERRHOST;
  171. /* create socket */
  172. if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  173. return ERRSOCK;
  174. setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
  175. /* connect to server */
  176. if (connect(s, &server, sizeof(server)) < 0)
  177. ret=ERRCONN;
  178. else {
  179. if (pfd) *pfd=s;
  180. /* create header */
  181. if (proxy) {
  182. sprintf(header,
  183. "%s http://%.128s:%d/%.256s HTTP/1.0\015\012User-Agent: %s\015\012%s\015\012",
  184. command,
  185. http_server,
  186. http_port,
  187. url,
  188. http_user_agent,
  189. additional_header
  190. );
  191. } else {
  192. sprintf(header,
  193. "%s /%.256s HTTP/1.0\015\012User-Agent: %s\015\012%s\015\012",
  194. command,
  195. url,
  196. http_user_agent,
  197. additional_header
  198. );
  199. }
  200. hlg=strlen(header);
  201. /* send header */
  202. if (write(s,header,hlg)!=hlg)
  203. ret= ERRWRHD;
  204. /* send data */
  205. else if (length && data && (write(s,data,length)!=length) )
  206. ret= ERRWRDT;
  207. else {
  208. /* read result & check */
  209. ret=http_read_line(s,header,MAXBUF-1);
  210. #ifdef VERBOSE
  211. fputs(header,stderr);
  212. putc('\n',stderr);
  213. #endif
  214. if (ret<=0)
  215. ret=ERRRDHD;
  216. else if (sscanf(header,"HTTP/1.%*d %03d",(int*)&ret)!=1)
  217. ret=ERRPAHD;
  218. else if (mode==KEEP_OPEN)
  219. return ret;
  220. }
  221. }
  222. /* close socket */
  223. close(s);
  224. return ret;
  225. }
  226. /*
  227. * Put data on the server
  228. *
  229. * This function sends data to the http data server.
  230. * The data will be stored under the ressource name filename.
  231. * returns a negative error code or a positive code from the server
  232. *
  233. * limitations: filename is truncated to first 256 characters
  234. * and type to 64.
  235. */
  236. http_retcode http_put(filename, data, length, overwrite, type)
  237. char *filename; /* name of the ressource to create */
  238. char *data; /* pointer to the data to send */
  239. int length; /* length of the data to send */
  240. int overwrite; /* flag to request to overwrite the ressource if it
  241. was already existing */
  242. char *type; /* type of the data, if NULL default type is used */
  243. {
  244. char header[MAXBUF];
  245. if (type)
  246. sprintf(header,"Content-length: %d\015\012Content-type: %.64s\015\012%s",
  247. length,
  248. type ,
  249. overwrite ? "Control: overwrite=1\015\012" : ""
  250. );
  251. else
  252. sprintf(header,"Content-length: %d\015\012%s",length,
  253. overwrite ? "Control: overwrite=1\015\012" : ""
  254. );
  255. return http_query("PUT",filename,header,CLOSE, data, length, NULL);
  256. }
  257. /*
  258. * Get data from the server
  259. *
  260. * This function gets data from the http data server.
  261. * The data is read from the ressource named filename.
  262. * Address of new new allocated memory block is filled in pdata
  263. * whose length is returned via plength.
  264. *
  265. * returns a negative error code or a positive code from the server
  266. *
  267. *
  268. * limitations: filename is truncated to first 256 characters
  269. */
  270. http_retcode http_get(filename, pdata, plength, typebuf)
  271. char *filename; /* name of the ressource to read */
  272. char **pdata; /* address of a pointer variable which will be set
  273. to point toward allocated memory containing read data.*/
  274. int *plength;/* address of integer variable which will be set to
  275. length of the read data */
  276. char *typebuf; /* allocated buffer where the read data type is returned.
  277. If NULL, the type is not returned */
  278. {
  279. http_retcode ret;
  280. char header[MAXBUF];
  281. char *pc;
  282. int fd;
  283. int n,length=-1;
  284. if (!pdata) return ERRNULL; else *pdata=NULL;
  285. if (plength) *plength=0;
  286. if (typebuf) *typebuf='\0';
  287. ret=http_query("GET",filename,"",KEEP_OPEN, NULL, 0, &fd);
  288. if (ret==200) {
  289. while (1) {
  290. n=http_read_line(fd,header,MAXBUF-1);
  291. #ifdef VERBOSE
  292. fputs(header,stderr);
  293. putc('\n',stderr);
  294. #endif
  295. if (n<=0) {
  296. close(fd);
  297. return ERRRDHD;
  298. }
  299. /* empty line ? (=> end of header) */
  300. if ( n>0 && (*header)=='\0') break;
  301. /* try to parse some keywords : */
  302. /* convert to lower case 'till a : is found or end of string */
  303. for (pc=header; (*pc!=':' && *pc) ; pc++) *pc=tolower(*pc);
  304. sscanf(header,"content-length: %d",&length);
  305. if (typebuf) sscanf(header,"content-type: %s",typebuf);
  306. }
  307. if (length<=0) {
  308. close(fd);
  309. return ERRNOLG;
  310. }
  311. if (plength) *plength=length;
  312. if (!(*pdata=malloc(length))) {
  313. close(fd);
  314. return ERRMEM;
  315. }
  316. n=http_read_buffer(fd,*pdata,length);
  317. close(fd);
  318. if (n!=length) ret=ERRRDDT;
  319. } else if (ret>=0) close(fd);
  320. return ret;
  321. }
  322. /*
  323. * Request the header
  324. *
  325. * This function outputs the header of thehttp data server.
  326. * The header is from the ressource named filename.
  327. * The length and type of data is eventually returned (like for http_get(3))
  328. *
  329. * returns a negative error code or a positive code from the server
  330. *
  331. * limitations: filename is truncated to first 256 characters
  332. */
  333. http_retcode http_head(filename, plength, typebuf)
  334. char *filename; /* name of the ressource to read */
  335. int *plength;/* address of integer variable which will be set to
  336. length of the data */
  337. char *typebuf; /* allocated buffer where the data type is returned.
  338. If NULL, the type is not returned */
  339. {
  340. /* mostly copied from http_get : */
  341. http_retcode ret;
  342. char header[MAXBUF];
  343. char *pc;
  344. int fd;
  345. int n,length=-1;
  346. if (plength) *plength=0;
  347. if (typebuf) *typebuf='\0';
  348. ret=http_query("HEAD",filename,"",KEEP_OPEN, NULL, 0, &fd);
  349. if (ret==200) {
  350. while (1) {
  351. n=http_read_line(fd,header,MAXBUF-1);
  352. #ifdef VERBOSE
  353. fputs(header,stderr);
  354. putc('\n',stderr);
  355. #endif
  356. if (n<=0) {
  357. close(fd);
  358. return ERRRDHD;
  359. }
  360. /* empty line ? (=> end of header) */
  361. if ( n>0 && (*header)=='\0') break;
  362. /* try to parse some keywords : */
  363. /* convert to lower case 'till a : is found or end of string */
  364. for (pc=header; (*pc!=':' && *pc) ; pc++) *pc=tolower(*pc);
  365. sscanf(header,"content-length: %d",&length);
  366. if (typebuf) sscanf(header,"content-type: %s",typebuf);
  367. }
  368. if (plength) *plength=length;
  369. close(fd);
  370. } else if (ret>=0) close(fd);
  371. return ret;
  372. }
  373. /*
  374. * Delete data on the server
  375. *
  376. * This function request a DELETE on the http data server.
  377. *
  378. * returns a negative error code or a positive code from the server
  379. *
  380. * limitations: filename is truncated to first 256 characters
  381. */
  382. http_retcode http_delete(filename)
  383. char *filename; /* name of the ressource to create */
  384. {
  385. return http_query("DELETE",filename,"",CLOSE, NULL, 0, NULL);
  386. }
  387. /* parses an url : setting the http_server and http_port global variables
  388. * and returning the filename to pass to http_get/put/...
  389. * returns a negative error code or 0 if sucessfully parsed.
  390. */
  391. http_retcode http_parse_url(url,pfilename)
  392. /* writeable copy of an url */
  393. char *url;
  394. /* address of a pointer that will be filled with allocated filename
  395. * the pointer must be equal to NULL before calling or it will be
  396. * automatically freed (free(3))
  397. */
  398. char **pfilename;
  399. {
  400. char *pc,c;
  401. http_port=80;
  402. if (http_server) {
  403. free(http_server);
  404. http_server=NULL;
  405. }
  406. if (*pfilename) {
  407. free(*pfilename);
  408. *pfilename=NULL;
  409. }
  410. if (strncasecmp("http://",url,7)) {
  411. #ifdef VERBOSE
  412. fprintf(stderr,"invalid url (must start with 'http://')\n");
  413. #endif
  414. return ERRURLH;
  415. }
  416. url+=7;
  417. for (pc=url,c=*pc; (c && c!=':' && c!='/');) c=*pc++;
  418. *(pc-1)=0;
  419. if (c==':') {
  420. if (sscanf(pc,"%d",&http_port)!=1) {
  421. #ifdef VERBOSE
  422. fprintf(stderr,"invalid port in url\n");
  423. #endif
  424. return ERRURLP;
  425. }
  426. for (pc++; (*pc && *pc!='/') ; pc++) ;
  427. if (*pc) pc++;
  428. }
  429. http_server=strdup(url);
  430. *pfilename= strdup ( c ? pc : "") ;
  431. #ifdef VERBOSE
  432. fprintf(stderr,"host=(%s), port=%d, filename=(%s)\n",
  433. http_server,http_port,*pfilename);
  434. #endif
  435. return OK0;
  436. }