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:
[email protected]; WWW:
http://www.ex-parrot.com/~chris/
+ *
+ */
+
+static const char rcsid[] = "$Id:$";
+
+#include <string.h>
+
+#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 @@
+<form method="post" action="lynxcgi:/tmp/testcgi">
+<input type="text" name="fish">
+<input type="submit">
+</form>
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}
};