commit - a7b9bb4d24e5f0d9ae6a1d67ac2224e0aef64d4e
commit + a87f6625658284c10597c2835135397ae698ad6c
blob - 5388023427098827fecf83c357f898d76678514e
blob + a60d7c0a55f19c7fa56a947d1abd7f3618467f89
--- gmid.h
+++ gmid.h
S_HANDSHAKE,
S_OPEN,
S_INITIALIZING,
- S_SENDING,
+ S_SENDING_FILE,
+ S_SENDING_CGI,
S_CLOSING,
};
struct tls *ctx;
char req[GEMINI_URL_LEN];
struct iri iri;
- int state;
+ int state, next;
int code;
const char *meta;
int fd, waiting_on_child;
- int child;
char sbuf[1024]; /* static buffer */
void *buf, *i; /* mmap buffer */
ssize_t len, off; /* mmap/static buffer */
void mark_nonblock(int);
void handle_handshake(struct pollfd*, struct client*);
void handle_open_conn(struct pollfd*, struct client*);
-int start_reply(struct pollfd*, struct client*, int, const char*);
+void start_reply(struct pollfd*, struct client*, int, const char*);
int start_cgi(const char*, const char*, const char*, struct pollfd*, struct client*);
void send_file(struct pollfd*, struct client*);
void send_dir(struct pollfd*, struct client*);
void cgi_poll_on_client(struct pollfd*, struct client*);
void handle_cgi(struct pollfd*, struct client*);
void close_conn(struct pollfd*, struct client*);
-void goodbye(struct pollfd*, struct client*, int, const char*);
void do_accept(int, struct tls*, struct pollfd*, struct client*);
void handle(struct pollfd*, struct client*);
void loop(struct tls*, int, int);
blob - 62fef97850b53b67c06472051910e83c05ff751d
blob + 4de3a7daccf45cf8e6aa56f61b5494aed92d8aa1
--- server.c
+++ server.c
return 0;
}
c->i = c->buf;
- if (!start_reply(fds, c, SUCCESS, mime(c->host, c->iri.path)))
- return 0;
- send_file(fds, c);
+ c->next = S_SENDING_FILE;
+ start_reply(fds, c, SUCCESS, mime(c->host, c->iri.path));
return 0;
case FILE_DIRECTORY:
case FILE_MISSING:
if (c->host->cgi != NULL && starts_with(c->iri.path, c->host->cgi))
return check_for_cgi(c->iri.path, c->iri.query, fds, c);
- goodbye(fds, c, NOT_FOUND, "not found");
+ start_reply(fds, c, NOT_FOUND, "not found");
return 0;
default:
}
err:
- goodbye(fds, c, NOT_FOUND, "not found");
+ start_reply(fds, c, NOT_FOUND, "not found");
return 0;
}
else
strncpy(c->req, "null", sizeof(c->req));
- goodbye(fds, c, BAD_REQUEST, "Wrong host or missing SNI");
+ start_reply(fds, c, BAD_REQUEST, "Wrong host or missing SNI");
}
void
}
if (!trim_req_iri(c->req) || !parse_iri(c->req, &c->iri, &parse_err)) {
- goodbye(fds, c, BAD_REQUEST, parse_err);
+ start_reply(fds, c, BAD_REQUEST, parse_err);
return;
}
/* XXX: we should check that the SNI matches the requested host */
if (strcmp(c->iri.schema, "gemini") || c->iri.port_no != conf.port) {
- goodbye(fds, c, PROXY_REFUSED, "won't proxy request");
+ start_reply(fds, c, PROXY_REFUSED, "won't proxy request");
return;
}
open_file(fds, c);
}
-int
+void
start_reply(struct pollfd *pfd, struct client *c, int code, const char *meta)
{
char buf[1030]; /* status + ' ' + max reply len + \r\n\0 */
assert(len < sizeof(buf));
switch (tls_write(c->ctx, buf, len)) {
+ case -1:
+ close_conn(pfd, c);
+ return;
case TLS_WANT_POLLIN:
pfd->events = POLLIN;
- return 0;
+ return;
case TLS_WANT_POLLOUT:
pfd->events = POLLOUT;
- return 0;
- default:
- log_request(c, buf, sizeof(buf));
- return 1;
+ return;
}
+
+ log_request(c, buf, sizeof(buf));
+
+ /* we don't need a body */
+ if (c->code != SUCCESS) {
+ close_conn(pfd, c);
+ return;
+ }
+
+ /* advance the state machine */
+ c->state = c->next;
+ handle(pfd, c);
}
int
close(c->fd);
if ((c->fd = recv_fd(exfd)) == -1) {
- goodbye(fds, c, TEMP_FAILURE, "internal server error");
+ start_reply(fds, c, TEMP_FAILURE, "internal server error");
return 0;
}
- c->child = 1;
- c->state = S_SENDING;
+ c->state = S_SENDING_CGI;
cgi_poll_on_child(fds, c);
c->code = -1;
/* handle_cgi(fds, c); */
ssize_t ret, len;
/* ensure the correct state */
- c->state = S_SENDING;
+ c->state = S_SENDING_FILE;
len = (c->buf + c->len) - c->i;
* - foo/$INDEX is a directory.
*/
if (c->iri.path == c->sbuf) {
- goodbye(fds, c, TEMP_REDIRECT, c->sbuf);
+ start_reply(fds, c, TEMP_REDIRECT, c->sbuf);
return;
}
/* redirect to url with the trailing / */
strlcat(c->sbuf, c->iri.path, sizeof(c->sbuf));
strlcat(c->sbuf, "/", sizeof(c->sbuf));
- goodbye(fds, c, TEMP_REDIRECT, c->sbuf);
+ start_reply(fds, c, TEMP_REDIRECT, c->sbuf);
return;
}
len = strlcat(c->sbuf, index, sizeof(c->sbuf));
if (len >= sizeof(c->sbuf)) {
- goodbye(fds, c, TEMP_FAILURE, "internal server error");
+ start_reply(fds, c, TEMP_FAILURE, "internal server error");
return;
}
}
void
-goodbye(struct pollfd *fds, struct client *c, int code, const char *meta)
-{
- if (!start_reply(fds, c, code, meta))
- return;
- close_conn(fds, c);
-}
-
-void
do_accept(int sock, struct tls *ctx, struct pollfd *fds, struct client *clients)
{
int i, fd;
fds[i].events = POLLIN;
clients[i].state = S_HANDSHAKE;
+ clients[i].next = S_SENDING_FILE;
clients[i].fd = -1;
- clients[i].child = 0;
clients[i].waiting_on_child = 0;
clients[i].buf = MAP_FAILED;
clients[i].addr = addr;
break;
case S_INITIALIZING:
- if (!start_reply(fds, client, client->code, client->meta))
- return;
+ start_reply(fds, client, client->code, client->meta);
+ break;
+
+ case S_SENDING_FILE:
+ send_file(fds, client);
+ break;
- if (client->code != SUCCESS) {
- /* we don't need a body */
- close_conn(fds, client);
- return;
- }
-
- client->state = S_SENDING;
-
- /* fallthrough */
-
- case S_SENDING:
- if (client->child)
- handle_cgi(fds, client);
- else
- send_file(fds, client);
+ case S_SENDING_CGI:
+ handle_cgi(fds, client);
break;
case S_CLOSING: