ksgi
/
output.c
687 строк · 16.0 Кб
1/* $Id$ */
2/*
3* Copyright (c) 2015, 2016, 2020 Kristaps Dzonsons <kristaps@bsd.lv>
4*
5* Permission to use, copy, modify, and distribute this software for any
6* purpose with or without fee is hereby granted, provided that the above
7* copyright notice and this permission notice appear in all copies.
8*
9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*/
17#include "config.h"18
19#include <arpa/inet.h>20
21#include <assert.h>22#include <ctype.h>23#include <inttypes.h>24#include <stdarg.h>25#include <stdint.h>26#include <stdio.h>27#include <stdlib.h>28#include <string.h>29#include <unistd.h>30#include <zlib.h>31
32#include "kcgi.h"33#include "extern.h"34
35/*
36* The state of our HTTP response.
37* We can be in KSTATE_HEAD, where we're printing HTTP headers; or
38* KSTATE_BODY, where we're printing the body parts.
39* So if we try to print a header when we're supposed to be in the body,
40* this will be caught.
41*/
42enum kstate {43KSTATE_HEAD = 0,44KSTATE_BODY
45};46
47/*
48* Interior data.
49* This is used for managing HTTP compression.
50*/
51struct kdata {52int debugging; /* debugging flags */53int fcgi; /* file descriptor or -1 */54int control; /* control socket or -1 */55char linebuf[80]; /* debugging output line buffer */56size_t linebufpos; /* position in line buffer */57uint64_t bytes; /* total bytes written */58uint16_t requestId; /* current requestId or 0 */59enum kstate state; /* see enum kstate */60gzFile gz; /* if not NULL, then compressor */61char *outbuf; /* buffered output */62size_t outbufpos; /* position in output buffer */63size_t outbufsz; /* size of output buffer */64int disabled; /* no more writers */65};66
67/*
68* A writer is allocated for use by a front-end formatter.
69* It is basically the bridge between the back-end writer (currently
70* operated by kdata_write) and the front-ends like kcgijson.
71*/
72struct kcgi_writer {73struct kdata *kdata; /* the back-end writer context */74int type; /* currently unused */75};76
77static char *78fcgi_header(uint8_t type, uint16_t requestId,79uint16_t contentLength, uint8_t paddingLength)80{
81static uint8_t header[8];82
83/* Masking probably not necessary: truncation. */84
85header[0] = 1;86header[1] = type;87header[2] = (requestId >> 8) & 0xff;88header[3] = requestId & 0xff;89header[4] = (contentLength >> 8) & 0xff;90header[5] = contentLength & 0xff;91header[6] = paddingLength;92header[7] = 0;93return((char *)header);94}
95
96/*
97* Write a `stdout' FastCGI packet.
98* This involves writing the header, then the data itself, then padding.
99* Returns KCGI_OK, KCGI_SYSTEM, or KCGI_HUP.
100*/
101static enum kcgi_err102fcgi_write(uint8_t type, const struct kdata *p, const char *buf, size_t sz)103{
104const char *pad = "\0\0\0\0\0\0\0\0";105char *head;106size_t rsz, padlen;107enum kcgi_err er = KCGI_OK;108
109/*110* Break up the data stream into FastCGI-capable chunks of at
111* most UINT16_MAX bytes.
112* Send each of these in its own FastCGI frame.
113* Pad to 8-byte boundary.
114*/
115
116do {117rsz = sz > UINT16_MAX ? UINT16_MAX : sz;118padlen = -rsz % 8;119head = fcgi_header(type, p->requestId, rsz, padlen);120if ((er = fullwritenoerr(p->fcgi, head, 8)) != KCGI_OK)121break;122if ((er = fullwritenoerr(p->fcgi, buf, rsz)) != KCGI_OK)123break;124if ((er = fullwritenoerr(p->fcgi, pad, padlen)) != KCGI_OK)125break;126sz -= rsz;127buf += rsz;128} while (sz > 0);129
130return er;131}
132
133/*
134* Flushes a buffer "buf" of size "sz" to the wire (stdout in the case
135* of CGI, the socket for FastCGI, and a gz stream for compression IFF
136* in body parts).
137* If sz is zero or buf is NULL, this is a no-op.
138* Return zero on failure (system error writing to output) or non-zero
139* on success.
140*/
141static enum kcgi_err142kdata_flush(struct kdata *p, const char *buf, size_t sz)143{
144
145if (sz == 0 || buf == NULL)146return KCGI_OK;147
148/*149* FIXME: make this work properly on all systems.
150* This is known (?) to break on FreeBSD: we may need to break
151* the uncompressed buffer into chunks that will not cause
152* EAGAIN to be raised.
153*/
154
155if (p->gz != NULL && p->state != KSTATE_HEAD) {156if (gzwrite(p->gz, buf, sz) == 0) {157kutil_warnx(NULL, NULL, "gzwrite");158return KCGI_SYSTEM;159}160return KCGI_OK;161}162
163return (p->fcgi == -1) ?164fullwritenoerr(STDOUT_FILENO, buf, sz) :165fcgi_write(6, p, buf, sz);166}
167
168/*
169* Drain the output buffer with kdata_flush().
170* Returns KCGI_OK, KCGI_SYSTEM, or KCGI_HUP.
171* XXX: if errors occur, outbufpos is zeroed as if we wrote the data.
172*/
173static enum kcgi_err174kdata_drain(struct kdata *p)175{
176enum kcgi_err er;177
178er = kdata_flush(p, p->outbuf, p->outbufpos);179p->outbufpos = 0;180return er;181}
182
183/*
184* In this function, we handle arbitrary writes of data to the output.
185* In the event of CGI, this will be to stdout; in the event of FastCGI,
186* this is to the wire.
187* We want to handle buffering of output, so we maintain an output
188* buffer that we fill and drain as needed.
189* This will end up calling kdata_flush(), directly or indirectly.
190* This will also handle debugging.
191* Returns KCGI_ENOMEM if any allocation failures occur during the
192* sequence, KCGI_SYSTEM if any errors occur writing to the output
193* channel, KCGI_HUP on channel hangup, or KCGI_OK on success.
194*/
195static enum kcgi_err196kdata_write(struct kdata *p, const char *buf, size_t sz)197{
198size_t i, max;199int newln;200enum kcgi_err er = KCGI_OK;201
202assert(p != NULL);203
204if (sz == 0 || buf == NULL)205return er;206
207/*208* If we're debugging writes, first copy as many bytes as
209* possible into the output line buffer, stopping when it's full
210* or when we have a newline. Keep flushing in these cases til
211* we have nothing left to add. We'll flush any stray bytes
212* when we get back here or close the connection.
213*/
214
215if (sz && (p->debugging & KREQ_DEBUG_WRITE))216for (i = 0, max = sizeof(p->linebuf); i < sz; ) {217newln = 0;218while (i < sz && p->linebufpos < max) {219p->linebuf[p->linebufpos] = buf[i++];220p->bytes++;221if (p->linebuf[p->linebufpos] == '\n') {222newln = 1;223break;224}225p->linebufpos++;226}227if (newln) {228kutil_info(NULL, NULL, "%lu-tx: %.*s",229(unsigned long)getpid(),230(int)p->linebufpos, p->linebuf);231p->linebufpos = 0;232} else if (p->linebufpos == max) {233kutil_info(NULL, NULL, "%lu-tx: %.*s...",234(unsigned long)getpid(),235(int)p->linebufpos, p->linebuf);236p->linebufpos = 0;237}238}239
240/*241* Short-circuit: if we have no output buffer, flush directly to
242* the wire.
243*/
244
245if (p->outbufsz == 0)246return kdata_flush(p, buf, sz);247
248/*249* If we want to accept new data and it exceeds the buffer size,
250* push out the entire existing buffer to start.
251* Then re-check if we exceed our buffer size.
252* If we do, then instead of filling into the temporary buffer
253* and looping until the new buffer is exhausted, just push the
254* whole thing out.
255* If we don't, then copy it into the buffer.
256*/
257
258if (p->outbufpos + sz > p->outbufsz) {259if ((er = kdata_drain(p)) != KCGI_OK)260return er;261if (sz > p->outbufsz)262return kdata_flush(p, buf, sz);263}264
265assert(p->outbufpos + sz <= p->outbufsz);266assert(p->outbuf != NULL);267memcpy(p->outbuf + p->outbufpos, buf, sz);268p->outbufpos += sz;269return er;270}
271
272enum kcgi_err273khttp_write(struct kreq *req, const char *buf, size_t sz)274{
275
276assert(req->kdata != NULL);277if (req->kdata->state != KSTATE_BODY)278return KCGI_FORM;279assert(!req->kdata->disabled);280
281/* This protects against buf == NULL or sz == 0. */282
283return kdata_write(req->kdata, buf, sz);284}
285
286enum kcgi_err287khttp_printf(struct kreq *req, const char *fmt, ...)288{
289char *buf;290int len;291va_list ap;292enum kcgi_err er;293
294if (fmt == NULL)295return KCGI_OK;296
297va_start(ap, fmt);298len = kxvasprintf(&buf, fmt, ap);299va_end(ap);300
301if (len == -1)302return KCGI_ENOMEM;303
304er = khttp_write(req, buf, (size_t)len);305free(buf);306return er;307}
308
309enum kcgi_err310khttp_puts(struct kreq *req, const char *cp)311{
312
313if (cp == NULL)314return KCGI_OK;315return khttp_write(req, cp, strlen(cp));316}
317
318enum kcgi_err319khttp_putc(struct kreq *req, int c)320{
321unsigned char cc = c;322
323return khttp_write(req, (char *)&cc, 1);324}
325
326enum kcgi_err327khttp_head(struct kreq *req, const char *key, const char *fmt, ...)328{
329va_list ap;330char *buf;331size_t ksz;332int len;333enum kcgi_err er;334
335assert(req->kdata != NULL);336assert(req->kdata->state == KSTATE_HEAD);337
338va_start(ap, fmt);339len = kxvasprintf(&buf, fmt, ap);340va_end(ap);341
342if (len == -1)343return KCGI_ENOMEM;344
345ksz = strlen(key);346if ((er = kdata_write(req->kdata, key, ksz)) != KCGI_OK)347goto out;348if ((er = kdata_write(req->kdata, ": ", 2)) != KCGI_OK)349goto out;350if ((er = kdata_write(req->kdata, buf, len)) != KCGI_OK)351goto out;352if ((er = kdata_write(req->kdata, "\r\n", 2)) != KCGI_OK)353goto out;354out:355free(buf);356return er;357}
358
359/*
360* Allocate our output data.
361* We accept the file descriptor for the FastCGI stream, if there's any.
362*/
363struct kdata *364kdata_alloc(int control, int fcgi, uint16_t requestId,365unsigned int debugging, const struct kopts *opts)366{
367struct kdata *p;368
369if ((p = kxcalloc(1, sizeof(struct kdata))) == NULL)370return NULL;371
372p->debugging = debugging;373p->fcgi = fcgi;374p->control = control;375p->requestId = requestId;376
377if (opts->sndbufsz > 0) {378p->outbufsz = opts->sndbufsz;379if ((p->outbuf = kxmalloc(p->outbufsz)) == NULL) {380free(p);381return NULL;382}383}384
385return p;386}
387
388/*
389* Two ways of doing this: with or without "flush".
390* If we're flushing, then we drain our output buffers to the output.
391* Either way, we then release all of our internal memory.
392*/
393void
394kdata_free(struct kdata *p, int flush)395{
396char buf[8];397uint32_t appStatus;398
399if (p == NULL)400return;401
402/* Debugging messages. */403
404if (flush && (p->debugging & KREQ_DEBUG_WRITE)) {405if (p->linebufpos)406kutil_info(NULL, NULL, "%lu-tx: %.*s",407(unsigned long)getpid(),408(int)p->linebufpos, p->linebuf);409p->linebufpos = 0;410kutil_info(NULL, NULL, "%lu-tx: %" PRIu64 " B",411(unsigned long)getpid(), p->bytes);412}413
414/* Remaining buffered data. */415
416if (flush)417kdata_drain(p);418
419free(p->outbuf);420
421/*422* If we're not FastCGI and we're not going to flush, then close
423* the file descriptors outright: we don't want gzclose()
424* flushing anything to the wire.
425*/
426
427if (!flush && p->fcgi == -1) {428close(STDOUT_FILENO);429close(STDIN_FILENO);430}431
432if (p->gz != NULL)433gzclose(p->gz);434
435if (p->fcgi == -1) {436free(p);437return;438}439
440/*441* If flushing, end the stream.
442* Note that we've already flushed our last FastCGI record to
443* the stream, but the standard implies that we need a blank
444* record to really shut this thing down.
445*/
446
447if (flush) {448fcgi_write(6, p, "", 0);449appStatus = htonl(EXIT_SUCCESS);450memset(buf, 0, 8);451memcpy(buf, &appStatus, sizeof(uint32_t));452
453/* End of request. */454
455fcgi_write(3, p, buf, 8);456
457/* Close out. */458
459close(p->fcgi);460fullwrite(p->control, &p->requestId, sizeof(uint16_t));461} else462close(p->fcgi);463
464free(p);465}
466
467/*
468* Try to enable compression on the output stream itself.
469* This function is only available with zlib.
470* We disallow compression on FastCGI streams because I don't yet have
471* the structure in place to copy the compressed data into a buffer then
472* write that out.
473* Set "ret" to zero if compression is not enabled, non-zero if enabled.
474* Returns zero if allocation errors occured (via gzdopen(3)), non-zero
475* otherwise.
476* On failure, "ret" is always zero.
477*/
478static int479kdata_compress(struct kdata *p, int *ret)480{
481
482*ret = 0;483assert(p->state == KSTATE_HEAD);484
485if (p->fcgi != -1)486return 1;487
488assert(p->gz == NULL);489if ((p->gz = gzdopen(STDOUT_FILENO, "w")) == NULL) {490kutil_warn(NULL, NULL, "gzdopen");491return 0;492}493*ret = 1;494return 1;495}
496
497/*
498* Begin the body sequence by draining the headers to the wire and
499* marking that the body has begun.
500* Returns KCGI_OK on success, KCGI_ENOMEM on memory exhaustion, and
501* KCGI_SYSTEM on wire-writing failure.
502*/
503static enum kcgi_err504kdata_body(struct kdata *p)505{
506enum kcgi_err er;507
508assert(p->state == KSTATE_HEAD);509
510if ((er = kdata_write(p, "\r\n", 2)) != KCGI_OK)511return er;512
513/*514* XXX: we always drain our buffer after the headers have been
515* written.
516* This incurs more chat on the wire, but also ensures that our
517* response gets to the server as quickly as possible.
518* Should an option be added to disable this?
519*/
520
521if ((er = kdata_drain(p)) != KCGI_OK)522return er;523
524p->state = KSTATE_BODY;525return KCGI_OK;526}
527
528enum kcgi_err529khttp_body(struct kreq *req)530{
531int hasreq = 0;532enum kcgi_err er;533const char *cp;534
535/*536* First determine if the request wants HTTP compression.
537* Use RFC 2616 14.3 as a guide for checking this: if we have
538* the "gzip" accept encoding and a non-zero quality, then use
539* compression.
540*/
541
542if (req->reqmap[KREQU_ACCEPT_ENCODING] != NULL) {543cp = req->reqmap[KREQU_ACCEPT_ENCODING]->val;544if ((cp = strstr(cp, "gzip")) != NULL) {545hasreq = 1;546cp += 4;547if (strncmp(cp, ";q=0", 4) == 0)548hasreq = '.' == cp[4];549}550}551
552/*553* Note: the underlying writing functions will not do any
554* compression even if we have compression enabled when in
555* header mode, so the order of these operations (enable
556* compression then write headers) is ok.
557*/
558
559if (hasreq) {560/*561* We could just ignore this error, which means gzdopen
562* failed, and just continue with hasreq=0.
563* However, if gzdopen fails (memory allocation), it
564* probably means other things are going to fail, so we
565* might as well just die now.
566*/
567
568if (!kdata_compress(req->kdata, &hasreq))569return KCGI_ENOMEM;570if (hasreq) {571er = khttp_head(req,572kresps[KRESP_CONTENT_ENCODING], "gzip");573if (er != KCGI_OK)574return er;575}576}577
578return kdata_body(req->kdata);579}
580
581enum kcgi_err582khttp_body_compress(struct kreq *req, int comp)583{
584int didcomp;585
586/*587* First, if we didn't request compression, go directly into the
588* body of the document.
589*/
590
591if (!comp)592return kdata_body(req->kdata);593
594/*595* If we do have compression requested, try enabling it on the
596* output stream.
597*/
598
599if (!kdata_compress(req->kdata, &didcomp))600return KCGI_ENOMEM;601else if (!didcomp)602return KCGI_FORM;603
604return kdata_body(req->kdata);605}
606
607/*
608* Allocate a writer.
609* This only works if we haven't disabled allocation of writers yet via
610* kcgi_writer_disable(), otherwise we abort().
611* Returns the writer or NULL on allocation (memory) failure.
612*/
613struct kcgi_writer *614kcgi_writer_get(struct kreq *r, int type)615{
616struct kcgi_writer *p;617
618if (r->kdata->disabled) {619kutil_warnx(NULL, NULL,620"kcgi_writer_get after kcgi_writer_disable");621abort();622}623
624if ((p = kxmalloc(sizeof(struct kcgi_writer))) != NULL)625p->kdata = r->kdata;626
627return p;628}
629
630/*
631* Disable further allocation of writers with kcgi_writer_get().
632* Following this, kcgi_writer_get() will abort.
633* This may be called as many times as desired: only the first time
634* makes a difference.
635*/
636void
637kcgi_writer_disable(struct kreq *r)638{
639
640r->kdata->disabled = 1;641}
642
643/*
644* Release an allocation by kcgi_writer_get().
645* May be called with a NULL-valued "p".
646*/
647void
648kcgi_writer_free(struct kcgi_writer *p)649{
650
651free(p);652}
653
654/*
655* Write "sz" bytes of "buf" into the output.
656* This doesn't necessarily mean that the output has been written: it
657* may be further buffered.
658* Returns KCGI_FORM and those from kdata_write().
659*/
660enum kcgi_err661kcgi_writer_write(struct kcgi_writer *p, const void *buf, size_t sz)662{
663
664if (p->kdata->state != KSTATE_BODY)665return KCGI_FORM;666return kdata_write(p->kdata, buf, sz);667}
668
669/*
670* Like kcgi_writer_write but for the NUL-terminated string.
671*/
672enum kcgi_err673kcgi_writer_puts(struct kcgi_writer *p, const char *cp)674{
675
676return kcgi_writer_write(p, cp, strlen(cp));677}
678
679/*
680* Like kcgi_writer_write but for a single character.
681*/
682enum kcgi_err683kcgi_writer_putc(struct kcgi_writer *p, char c)684{
685
686return kcgi_writer_write(p, &c, 1);687}
688