ksgi

Форк
0
/
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
 */
42
enum	kstate {
43
	KSTATE_HEAD = 0,
44
	KSTATE_BODY
45
};
46

47
/*
48
 * Interior data.
49
 * This is used for managing HTTP compression.
50
 */
51
struct	kdata {
52
	int		 debugging; /* debugging flags */
53
	int		 fcgi; /* file descriptor or -1 */
54
	int		 control; /* control socket or -1 */
55
	char		 linebuf[80]; /* debugging output line buffer */
56
	size_t		 linebufpos; /* position in line buffer */
57
	uint64_t	 bytes; /* total bytes written */
58
	uint16_t	 requestId; /* current requestId or 0 */
59
	enum kstate	 state; /* see enum kstate */
60
	gzFile		 gz; /* if not NULL, then compressor */
61
	char		*outbuf; /* buffered output */
62
	size_t		 outbufpos; /* position in output buffer */
63
	size_t		 outbufsz; /* size of output buffer */
64
	int		 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
 */
72
struct	kcgi_writer {
73
	struct kdata	*kdata; /* the back-end writer context */
74
	int		 type; /* currently unused */
75
};
76

77
static char *
78
fcgi_header(uint8_t type, uint16_t requestId, 
79
	uint16_t contentLength, uint8_t paddingLength)
80
{
81
	static uint8_t	header[8];
82

83
	/* Masking probably not necessary: truncation. */
84

85
	header[0] = 1;
86
	header[1] = type;
87
	header[2] = (requestId >> 8) & 0xff;
88
	header[3] = requestId & 0xff;
89
	header[4] = (contentLength >> 8) & 0xff;
90
	header[5] = contentLength & 0xff;
91
	header[6] = paddingLength;
92
	header[7] = 0;
93
	return((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
 */
101
static enum kcgi_err
102
fcgi_write(uint8_t type, const struct kdata *p, const char *buf, size_t sz)
103
{
104
	const char	*pad = "\0\0\0\0\0\0\0\0";
105
	char		*head;
106
	size_t	 	 rsz, padlen;
107
	enum 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

116
	do {
117
		rsz = sz > UINT16_MAX ? UINT16_MAX : sz;
118
		padlen = -rsz % 8;
119
		head = fcgi_header(type, p->requestId, rsz, padlen);
120
		if ((er = fullwritenoerr(p->fcgi, head, 8)) != KCGI_OK)
121
			break;
122
		if ((er = fullwritenoerr(p->fcgi, buf, rsz)) != KCGI_OK)
123
			break;
124
		if ((er = fullwritenoerr(p->fcgi, pad, padlen)) != KCGI_OK)
125
			break;
126
		sz -= rsz;
127
		buf += rsz;
128
	} while (sz > 0);
129

130
	return 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
 */
141
static enum kcgi_err
142
kdata_flush(struct kdata *p, const char *buf, size_t sz)
143
{
144

145
	if (sz == 0 || buf == NULL)
146
		return 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

155
	if (p->gz != NULL && p->state != KSTATE_HEAD) {
156
		if (gzwrite(p->gz, buf, sz) == 0) {
157
			kutil_warnx(NULL, NULL, "gzwrite");
158
			return KCGI_SYSTEM;
159
		}
160
		return KCGI_OK;
161
	}
162

163
	return (p->fcgi == -1) ?
164
		fullwritenoerr(STDOUT_FILENO, buf, sz) :
165
		fcgi_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
 */
173
static enum kcgi_err
174
kdata_drain(struct kdata *p)
175
{
176
	enum kcgi_err	 er;
177

178
	er = kdata_flush(p, p->outbuf, p->outbufpos);
179
	p->outbufpos = 0;
180
	return 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
 */
195
static enum kcgi_err
196
kdata_write(struct kdata *p, const char *buf, size_t sz)
197
{
198
	size_t	 	 i, max;
199
	int		 newln;
200
	enum kcgi_err	 er = KCGI_OK;
201

202
	assert(p != NULL);
203

204
	if (sz == 0 || buf == NULL)
205
		return 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

215
	if (sz && (p->debugging & KREQ_DEBUG_WRITE))
216
		for (i = 0, max = sizeof(p->linebuf); i < sz; ) {
217
			newln = 0;
218
			while (i < sz && p->linebufpos < max) {
219
				p->linebuf[p->linebufpos] = buf[i++];
220
				p->bytes++;
221
				if (p->linebuf[p->linebufpos] == '\n') {
222
					newln = 1;
223
					break;
224
				}
225
				p->linebufpos++;
226
			}
227
			if (newln) {
228
				kutil_info(NULL, NULL, "%lu-tx: %.*s",
229
					(unsigned long)getpid(), 
230
					(int)p->linebufpos, p->linebuf);
231
				p->linebufpos = 0;
232
			} else if (p->linebufpos == max) {
233
				kutil_info(NULL, NULL, "%lu-tx: %.*s...",
234
					(unsigned long)getpid(), 
235
					(int)p->linebufpos, p->linebuf);
236
				p->linebufpos = 0;
237
			}
238
		}
239

240
	/* 
241
	 * Short-circuit: if we have no output buffer, flush directly to
242
	 * the wire.
243
	 */
244

245
	if (p->outbufsz == 0)
246
		return 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

258
	if (p->outbufpos + sz > p->outbufsz) {
259
		if ((er = kdata_drain(p)) != KCGI_OK)
260
			return er;
261
		if (sz > p->outbufsz)
262
			return kdata_flush(p, buf, sz);
263
	}
264

265
	assert(p->outbufpos + sz <= p->outbufsz);
266
	assert(p->outbuf != NULL);
267
	memcpy(p->outbuf + p->outbufpos, buf, sz);
268
	p->outbufpos += sz;
269
	return er;
270
}
271

272
enum kcgi_err
273
khttp_write(struct kreq *req, const char *buf, size_t sz)
274
{
275

276
	assert(req->kdata != NULL);
277
	if (req->kdata->state != KSTATE_BODY)
278
		return KCGI_FORM;
279
	assert(!req->kdata->disabled);
280

281
	/* This protects against buf == NULL or sz == 0. */
282

283
	return kdata_write(req->kdata, buf, sz);
284
}
285

286
enum kcgi_err
287
khttp_printf(struct kreq *req, const char *fmt, ...)
288
{
289
	char		*buf;
290
	int		 len;
291
	va_list		 ap;
292
	enum kcgi_err	 er;
293

294
	if (fmt == NULL)
295
		return KCGI_OK;
296

297
	va_start(ap, fmt);
298
	len = kxvasprintf(&buf, fmt, ap);
299
	va_end(ap);
300

301
	if (len == -1)
302
		return KCGI_ENOMEM;
303

304
	er = khttp_write(req, buf, (size_t)len);
305
	free(buf);
306
	return er;
307
}
308

309
enum kcgi_err
310
khttp_puts(struct kreq *req, const char *cp)
311
{
312

313
	if (cp == NULL)
314
		return KCGI_OK;
315
	return khttp_write(req, cp, strlen(cp));
316
}
317

318
enum kcgi_err
319
khttp_putc(struct kreq *req, int c)
320
{
321
	unsigned char	cc = c;
322

323
	return khttp_write(req, (char *)&cc, 1);
324
}
325

326
enum kcgi_err
327
khttp_head(struct kreq *req, const char *key, const char *fmt, ...)
328
{
329
	va_list		 ap;
330
	char		*buf;
331
	size_t		 ksz;
332
	int		 len;
333
	enum kcgi_err	 er;
334

335
	assert(req->kdata != NULL);
336
	assert(req->kdata->state == KSTATE_HEAD);
337

338
	va_start(ap, fmt);
339
	len = kxvasprintf(&buf, fmt, ap);
340
	va_end(ap);
341

342
	if (len == -1) 
343
		return KCGI_ENOMEM;
344

345
	ksz = strlen(key);
346
	if ((er = kdata_write(req->kdata, key, ksz)) != KCGI_OK)
347
		goto out;
348
	if ((er = kdata_write(req->kdata, ": ", 2)) != KCGI_OK)
349
		goto out;
350
	if ((er = kdata_write(req->kdata, buf, len)) != KCGI_OK)
351
		goto out;
352
	if ((er = kdata_write(req->kdata, "\r\n", 2)) != KCGI_OK)
353
		goto out;
354
out:
355
	free(buf);
356
	return er;
357
}
358

359
/*
360
 * Allocate our output data.
361
 * We accept the file descriptor for the FastCGI stream, if there's any.
362
 */
363
struct kdata *
364
kdata_alloc(int control, int fcgi, uint16_t requestId, 
365
	unsigned int debugging, const struct kopts *opts)
366
{
367
	struct kdata	*p;
368

369
	if ((p = kxcalloc(1, sizeof(struct kdata))) == NULL)
370
		return NULL;
371

372
	p->debugging = debugging;
373
	p->fcgi = fcgi;
374
	p->control = control;
375
	p->requestId = requestId;
376

377
	if (opts->sndbufsz > 0) {
378
		p->outbufsz = opts->sndbufsz;
379
		if ((p->outbuf = kxmalloc(p->outbufsz)) == NULL) {
380
			free(p);
381
			return NULL;
382
		}
383
	} 
384

385
	return 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
 */
393
void
394
kdata_free(struct kdata *p, int flush)
395
{
396
	char	 	 buf[8];
397
	uint32_t 	 appStatus;
398

399
	if (p == NULL)
400
		return;
401

402
	/* Debugging messages. */
403

404
	if (flush && (p->debugging & KREQ_DEBUG_WRITE)) {
405
		if (p->linebufpos)
406
			kutil_info(NULL, NULL, "%lu-tx: %.*s",
407
				(unsigned long)getpid(), 
408
				(int)p->linebufpos, p->linebuf);
409
		p->linebufpos = 0;
410
		kutil_info(NULL, NULL, "%lu-tx: %" PRIu64 " B",
411
			(unsigned long)getpid(), p->bytes);
412
	}
413

414
	/* Remaining buffered data. */
415

416
	if (flush) 
417
		kdata_drain(p);
418

419
	free(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

427
	if (!flush && p->fcgi == -1) {
428
		close(STDOUT_FILENO);
429
		close(STDIN_FILENO);
430
	}
431

432
	if (p->gz != NULL)
433
		gzclose(p->gz);
434

435
	if (p->fcgi == -1) {
436
		free(p);
437
		return;
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

447
	if (flush) {
448
		fcgi_write(6, p, "", 0);
449
		appStatus = htonl(EXIT_SUCCESS);
450
		memset(buf, 0, 8);
451
		memcpy(buf, &appStatus, sizeof(uint32_t));
452

453
		/* End of request. */
454

455
		fcgi_write(3, p, buf, 8);
456

457
		/* Close out. */
458

459
		close(p->fcgi);
460
		fullwrite(p->control, &p->requestId, sizeof(uint16_t));
461
	} else
462
		close(p->fcgi);
463

464
	free(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
 */
478
static int
479
kdata_compress(struct kdata *p, int *ret)
480
{
481

482
	*ret = 0;
483
	assert(p->state == KSTATE_HEAD);
484

485
	if (p->fcgi != -1)
486
		return 1;
487

488
	assert(p->gz == NULL);
489
	if ((p->gz = gzdopen(STDOUT_FILENO, "w")) == NULL) {
490
		kutil_warn(NULL, NULL, "gzdopen");
491
		return 0;
492
	}
493
	*ret = 1;
494
	return 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
 */
503
static enum kcgi_err
504
kdata_body(struct kdata *p)
505
{
506
	enum kcgi_err	 er;
507

508
	assert(p->state == KSTATE_HEAD);
509

510
	if ((er = kdata_write(p, "\r\n", 2)) != KCGI_OK)
511
		return 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

521
	if ((er = kdata_drain(p)) != KCGI_OK)
522
		return er;
523

524
	p->state = KSTATE_BODY;
525
	return KCGI_OK;
526
}
527

528
enum kcgi_err
529
khttp_body(struct kreq *req)
530
{
531
	int	 	 hasreq = 0;
532
	enum kcgi_err	 er;
533
	const 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

542
	if (req->reqmap[KREQU_ACCEPT_ENCODING] != NULL) {
543
		cp = req->reqmap[KREQU_ACCEPT_ENCODING]->val;
544
		if ((cp = strstr(cp, "gzip")) != NULL) {
545
			hasreq = 1;
546
			cp += 4;
547
			if (strncmp(cp, ";q=0", 4) == 0) 
548
				hasreq = '.' == 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

559
	if (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

568
		if (!kdata_compress(req->kdata, &hasreq))
569
			return KCGI_ENOMEM;
570
		if (hasreq) {
571
			er = khttp_head(req, 
572
				kresps[KRESP_CONTENT_ENCODING], "gzip");
573
			if (er != KCGI_OK)
574
				return er;
575
		}
576
	}
577

578
	return kdata_body(req->kdata);
579
}
580

581
enum kcgi_err
582
khttp_body_compress(struct kreq *req, int comp)
583
{
584
	int	 didcomp;
585

586
	/* 
587
	 * First, if we didn't request compression, go directly into the
588
	 * body of the document.
589
	 */
590

591
	if (!comp)
592
		return kdata_body(req->kdata);
593

594
	/*
595
	 * If we do have compression requested, try enabling it on the
596
	 * output stream.
597
	 */
598

599
	if (!kdata_compress(req->kdata, &didcomp))
600
		return KCGI_ENOMEM;
601
	else if (!didcomp)
602
		return KCGI_FORM;
603

604
	return 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
 */
613
struct kcgi_writer *
614
kcgi_writer_get(struct kreq *r, int type)
615
{
616
	struct kcgi_writer	*p;
617

618
	if (r->kdata->disabled) {
619
		kutil_warnx(NULL, NULL, 
620
			"kcgi_writer_get after kcgi_writer_disable");
621
		abort();
622
	}
623

624
	if ((p = kxmalloc(sizeof(struct kcgi_writer))) != NULL)
625
		p->kdata = r->kdata;
626

627
	return 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
 */
636
void
637
kcgi_writer_disable(struct kreq *r)
638
{
639

640
	r->kdata->disabled = 1;
641
}
642

643
/*
644
 * Release an allocation by kcgi_writer_get().
645
 * May be called with a NULL-valued "p".
646
 */
647
void
648
kcgi_writer_free(struct kcgi_writer *p)
649
{
650

651
	free(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
 */
660
enum kcgi_err
661
kcgi_writer_write(struct kcgi_writer *p, const void *buf, size_t sz)
662
{
663

664
	if (p->kdata->state != KSTATE_BODY)
665
		return KCGI_FORM;
666
	return kdata_write(p->kdata, buf, sz);
667
}
668

669
/*
670
 * Like kcgi_writer_write but for the NUL-terminated string.
671
 */
672
enum kcgi_err
673
kcgi_writer_puts(struct kcgi_writer *p, const char *cp)
674
{
675

676
	return kcgi_writer_write(p, cp, strlen(cp));
677
}
678

679
/*
680
 * Like kcgi_writer_write but for a single character.
681
 */
682
enum kcgi_err
683
kcgi_writer_putc(struct kcgi_writer *p, char c)
684
{
685

686
	return kcgi_writer_write(p, &c, 1);
687
}
688

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.