diff -urN links-2.1pre7.orig/Makefile.am links-2.1pre7/Makefile.am --- links-2.1pre7.orig/Makefile.am Sat Jun 8 14:11:51 2002 +++ links-2.1pre7/Makefile.am Tue Feb 4 19:59:00 2003 @@ -13,7 +13,7 @@ else endif -links_SOURCES=af_unix.c beos.c bfu.c bookmarks.c builtin.c cache.c charsets.c connect.c context.c cookies.c default.c dip.c dither.c dns.c drivers.c error.c file.c finger.c font_include.c framebuffer.c ftp.c gif.c html.c html_gr.c html_r.c html_tbl.c http.c https.c img.c imgcache.c ipret.c javascr.c javascript.c jpeg.c jsint.c kbd.c language.c links_icon.c listedit.c lru.c mailto.c main.c menu.c memory.c md5.c md5hl.c ns.c objreq.c os_dep.c pmshell.c png.c pomocny.c sched.c select.c session.c svgalib.c terminal.c tiff.c types.c url.c view.c view_gr.c win32.c x.c xbm.c links.h cfg.h os_dep.h os_depx.h setup.h codepage.h language.h codepage.inc entity.inc uni_7b.inc language.inc arrow.inc md5.h ns.h struct.h tree.h typy.h ipret.h javascript.h builtin.h builtin_keys.h bits.h +links_SOURCES=af_unix.c beos.c bfu.c bookmarks.c builtin.c cache.c charsets.c connect.c context.c cookies.c default.c dip.c dither.c dns.c drivers.c error.c file.c lynxcgi.c finger.c font_include.c framebuffer.c ftp.c gif.c html.c html_gr.c html_r.c html_tbl.c http.c https.c img.c imgcache.c ipret.c javascr.c javascript.c jpeg.c jsint.c kbd.c language.c links_icon.c listedit.c lru.c mailto.c main.c menu.c memory.c md5.c md5hl.c ns.c objreq.c os_dep.c pmshell.c png.c pomocny.c sched.c select.c session.c svgalib.c terminal.c tiff.c types.c url.c view.c view_gr.c win32.c x.c xbm.c links.h cfg.h os_dep.h os_depx.h setup.h codepage.h language.h codepage.inc entity.inc uni_7b.inc language.inc arrow.inc md5.h ns.h struct.h tree.h typy.h ipret.h javascript.h builtin.h builtin_keys.h bits.h dist-hook: #remove the symlinka: diff -urN links-2.1pre7.orig/links.h links-2.1pre7/links.h --- links-2.1pre7.orig/links.h Sat Nov 2 17:22:41 2002 +++ links-2.1pre7/links.h Tue Feb 4 19:53:50 2003 @@ -1124,6 +1124,10 @@ void telnet_func(struct session *, unsigned char *); void tn3270_func(struct session *, unsigned char *); +/* lynxcgi.c */ + +void lynxcgi_func(struct connection *); + /* kbd.c */ #define BM_BUTT 15 diff -urN links-2.1pre7.orig/lynxcgi.c links-2.1pre7/lynxcgi.c --- links-2.1pre7.orig/lynxcgi.c Thu Jan 1 01:00:00 1970 +++ links-2.1pre7/lynxcgi.c Tue Feb 4 21:59:10 2003 @@ -0,0 +1,315 @@ +/* + * lynxcgi.c: + * Implementation of lynxcgi: protocol. + * + * Cf. http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html + * + * Copyright (c) 2003 Chris Lightfoot. All rights reserved. + * Email: chris@ex-parrot.com; WWW: http://www.ex-parrot.com/~chris/ + * + */ + +static const char rcsid[] = "$Id:$"; + +#include + +#include "links.h" + +unsigned char *get_line_from_stream(FILE *fp) { + unsigned char *buf; + int c; + size_t i, len; + buf = malloc(len = 128); + i = 0; + while ((c = getc(fp)) != EOF) { + if (c == '\n') { + if (i > 0 && buf[i - 1] == '\r') + buf[i - 1] = 0; + else + buf[i] = 0; + break; + } + buf[i] = (unsigned char)c; + ++i; + if (i == len) + buf = realloc(buf, len *= 2); + } + + if (c == EOF && (ferror(fp) || i == 0)) { + free(buf); + return NULL; + } + + return buf; +} + +int parse_nph_response_from_stream(struct cache_entry *e, FILE *fp, unsigned char *firstline) { + return 0; + /* not implemented yet */ +} + +int parse_cgi_response_from_stream(struct cache_entry *e, FILE *fp) { + unsigned char *line, *hdr, *val, *http_resp_line = NULL, *http_hdrs = NULL, *data; + size_t http_hdrs_len = 0, http_hdrs_alloc, data_len = 0, data_alloc; + int c; + + fseek(fp, 0, SEEK_SET); + + line = get_line_from_stream(fp); + if (!line) + return 0; + + /* Handle NPH case. */ + if (strncmp(line, "HTTP/1.1 ", 9) == 0 || strncmp(line, "HTTP/1.0 ", 9) == 0) + return parse_nph_response_from_stream(e, fp, line); + + http_hdrs = malloc(http_hdrs_alloc = 1024); + *http_hdrs = 0; + + /* Handle normal response. */ + do { + size_t hdr_len, val_len; + /* end of headers; rest of data is just regular output. */ + if (*line == 0) { + free(line); + break; + } + + hdr = line; + val = strchr(line, ':'); + if (!val) + /* Bogus header. */ + continue; + + *val++ = 0; + val += strspn(val, " "); + + hdr_len = strlen(hdr); + val_len = strlen(val); + + if (strcasecmp(hdr, "Status") == 0 && !http_resp_line) { + /* Have HTTP header. */ + http_resp_line = malloc(10 + strlen(val)); + strcpy(http_resp_line, "HTTP/1.1 "); + strcat(http_resp_line, val); + } else if (strcasecmp(hdr, "Location") == 0) { + /* Do something about this. */ + } else { + /* Generic header, just save it. */ + while (http_hdrs_len + hdr_len + val_len + 4 > http_hdrs_alloc) + http_hdrs = realloc(http_hdrs, http_hdrs_alloc *= 2); + + strcpy(http_hdrs + http_hdrs_len, hdr); http_hdrs_len += hdr_len; + strcpy(http_hdrs + http_hdrs_len, ": "); http_hdrs_len += 2; + strcpy(http_hdrs + http_hdrs_len, val); http_hdrs_len += val_len; + strcpy(http_hdrs + http_hdrs_len, "\r\n"); http_hdrs_len += 2; + } + + free(line); + } while (line = get_line_from_stream(fp)); + + if (ferror(fp)) { + free(http_hdrs); + if (http_resp_line) + free(http_resp_line); + return 0; + } + + if (!http_resp_line) + http_resp_line = strdup("HTTP/1.1 200 OK"); + + data = mem_alloc(data_alloc = 1024); + while ((c = getc(fp)) != EOF) { + data[data_len++] = (unsigned char)c; + if (data_len == data_alloc) + data = mem_realloc(data, data_alloc *= 2); + } + + if (ferror(fp)) { + free(http_hdrs); + free(http_resp_line); + mem_free(data); + return 0; + } + + /* OK, now have header and data. Save in cache object. */ + e->head = mem_alloc(strlen(http_resp_line) + 2 + http_hdrs_len + 1); + strcpy(e->head, http_resp_line); + strcat(e->head, "\r\n"); + strcat(e->head, http_hdrs); + + add_fragment(e, 0, data, data_len); /* copies data, apparently */ + truncate_entry(e, data_len, 1); + + mem_free(data); + + free(http_resp_line); + free(http_hdrs); + + return 1; +} + +/* Lazy. All done with temporary files.... */ +int run_cgi_script(struct cache_entry *e, unsigned char *script, unsigned char *query, unsigned char *post_ct, unsigned char *post_data, size_t post_len) { + pid_t scriptpid; + FILE *input = NULL, *output = NULL; + int ret = 0; + + if (post_data) { + input = tmpfile(); + fwrite(post_data, 1, post_len, input); + fflush(input); + fseek(input, 0, SEEK_SET); + } + + output = tmpfile(); + + scriptpid = fork(); + if (scriptpid == -1) { + if (input) + fclose(input); + fclose(output); + return 0; + } else if (scriptpid == 0) { + unsigned char *sn; + char **argv[] = {NULL, NULL}; + + /* Never call stdio stuff on input/output no more.... */ + close(0); + close(1); + if (input) + dup2(fileno(input), 0); + dup2(fileno(output), 1); + + /* Environment variables for the script. */ + putenv("GATEWAY_INTERFACE=CGI/1.1"); + sn = malloc(strlen(script) + sizeof("SCRIPT_NAME=lynxcgi:")); + sprintf(sn, "SCRIPT_NAME=lynxcgi:%s", script); + if (query) { + unsigned char *qs; + qs = malloc(strlen(query) + sizeof("QUERY_STRING=")); + sprintf(qs, "QUERY_STRING=%s", query); + putenv(qs); + } + putenv("REMOTE_ADDR=127.0.0.1"); + putenv("REMOTE_HOST=localhost"); + /* REMOTE_IDENT/REMOTE_USER? */ + putenv("SERVER_NAME=localhost"); + putenv("SERVER_PORT=0"); + putenv("SERVER_PROTOCOL=HTTP/1.1"); /* bogus */ + putenv("SERVER_SOFTWARE=links-lynxcgi"); + + if (post_data) { + unsigned char *ct, *cl; + ct = malloc(strlen(post_ct) + sizeof("CONTENT_TYPE=")); + sprintf(ct, "CONTENT_TYPE=%s", post_ct); + putenv(ct); + cl = malloc(16 + sizeof("CONTENT_LENGTH")); + sprintf(cl, "CONTENT_LENGTH=%d", post_len); + putenv(cl); + } else + putenv("REQUEST_METHOD=GET"); + + /* Have a go at execing the script.... */ + execl(script, script, NULL); + + /* Oops, well, that didn't work. But hey! we have a protocol for + * dealing with that! ... but sadly links isn't very good with + * error messages. Oh well. */ + printf("Content-Type: text/plain\nStatus: 500 script error; %s: %s\n\nScript error: %s: %s\n\n", script, strerror(errno), script, strerror(errno)); + + _exit(255); + } else { + /* Wait for script to complete. */ + int status; + void (*oldsigchld)(int); + + /* Hack. We switch off the main SIGCHLD signal handler until our child + * process completes. */ + oldsigchld = signal(SIGCHLD, SIG_DFL); + + while (waitpid(scriptpid, &status, 0) == -1 && errno == EINTR); + /* XXX need timeout here. */ + + signal(SIGCHLD, oldsigchld); + + if (!WIFEXITED(status)) { + /* Something bad happened. */ + } else { + /* OK, parse script output. */ + ret = parse_cgi_response_from_stream(e, output); + } + } + + fclose(output); + + return ret; +} + +void lynxcgi_func(struct connection *c) { + unsigned char *script = NULL, *query, *post_ct = NULL, *post_data = NULL, *p; + size_t post_len; + struct cache_entry *e; + + if (anonymous || strlen(c->url) < 9 || c->url[8] != '/') { + setcstate(c, S_BAD_URL); + abort_connection(c); + return; + } + + /* Obtain name of script and query. */ + script = strdup(c->url + 8); + + if ((p = strchr(script, POST_CHAR))) { + /* This is mindlessly ugly. POST data is appended to the URL after + * an occurence of POST_CHAR. The sentinel is followed by the + * content-type of the data, then a \n, then the data itself encoded + * in hex. Gag me with a spoon. */ + *p = 0; + post_ct = ++p; + p = strchr(p, '\n'); + + if (!p) { + setcstate(c, S_BAD_URL); + goto finish; + } + *p++ = 0; + + post_data = p; + post_len = 0; + while (p[0] && p[1]) { + int h1, h2; + /* from http.c */ + h1 = p[0] <= '9' ? p[0] - '0' : p[0] >= 'A' ? upcase(p[0]) - 'A' + 10 : 0; + if (h1 < 0 || h1 >= 16) h1 = 0; + h2 = p[1] <= '9' ? p[1] - '0' : p[1] >= 'A' ? upcase(p[1]) - 'A' + 10 : 0; + if (h2 < 0 || h2 >= 16) h2 = 0; + post_data[post_len++] = h1 * 16 + h2; + p += 2; + } + post_data[post_len] = 0; + } + + /* Extract query if present. */ + query = strchr(script, '?'); + if (query) + *query++ = 0; + + /* OK, now we need to fork and exec the CGI script. */ + get_cache_entry(c->url, &e); + if (e->head) + mem_free(e->head); + + if (run_cgi_script(e, script, query, post_ct, post_data, post_len)) { + c->cache = e; + c->cache->incomplete = 0; + setcstate(c, S_OK); + } else + setcstate(c, S_FILE_ERROR); /* close enough */ + + +finish: + if (script) + free(script); + abort_connection(c); +} diff -urN links-2.1pre7.orig/test.html links-2.1pre7/test.html --- links-2.1pre7.orig/test.html Thu Jan 1 01:00:00 1970 +++ links-2.1pre7/test.html Tue Feb 4 21:19:46 2003 @@ -0,0 +1,4 @@ +
+ + +
diff -urN links-2.1pre7.orig/url.c links-2.1pre7/url.c --- links-2.1pre7.orig/url.c Mon Jun 17 14:25:42 2002 +++ links-2.1pre7/url.c Tue Feb 4 19:53:49 2003 @@ -26,6 +26,7 @@ #ifdef JS {"javascript", 0, NULL, javascript_func, 1, 0, 0}, #endif + {"lynxcgi", 0, lynxcgi_func, NULL, 1, 0, 0}, {NULL, 0, NULL} };