ksgi

Форк
0
/
fcgi.c 
760 строк · 17.2 Кб
1
/*	$Id$ */
2
/*
3
 * Copyright (c) 2015--2016, 2018 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 <sys/ioctl.h>
20
#include <sys/socket.h>
21

22
#include <assert.h>
23
#include <errno.h>
24
#include <fcntl.h>
25
#include <inttypes.h>
26
#include <limits.h>
27
#include <poll.h>
28
#include <signal.h>
29
#include <stdarg.h>
30
#include <stdint.h>
31
#include <stdlib.h>
32
#include <stdio.h> /* BUFSIZ */
33
#include <string.h>
34
#include <unistd.h>
35

36
#include "kcgi.h"
37
#include "extern.h"
38

39
struct	kfcgi {
40
	const struct kvalid	 *keys;
41
	size_t			  keysz;
42
	const char *const	 *mimes;
43
	size_t			  mimesz;
44
	size_t			  defmime;
45
	unsigned int		  debugging;
46
	const char *const	 *pages;
47
	size_t			  pagesz;
48
	size_t			  defpage;
49
	const struct kmimemap 	 *mimemap;
50
	pid_t			  work_pid;
51
	pid_t			  sock_pid;
52
	int			  work_dat;
53
	int			  sock_ctl;
54
	struct kopts		  opts;
55
	void			 *arg;
56
};
57

58
static	volatile sig_atomic_t sig = 0;
59

60
static void
61
dosignal(int arg)
62
{
63

64
	sig = 1;
65
}
66

67
/*
68
 * This is our control process.
69
 * It listens for FastCGI connections on the manager connection in
70
 * traditional mode ("fdaccept") xor extended mode ("fdfiled").
71
 * When it has one, it reads and passes to the worker (sibling) process,
72
 * which will be parsing the data.
73
 * When the worker has finished, it passes back the request identifier,
74
 * which this passes to the main application for output.
75
 * If the current FastCGI connection closes, abandon it and wait for the
76
 * next.
77
 * This exits with the manager connection closes.
78
 * On exit, it will close the fdaccept or fdfiled descriptor.
79
 */
80
static int
81
kfcgi_control(int work, int ctrl, 
82
	int fdaccept, int fdfiled, pid_t worker)
83
{
84
	struct sockaddr_storage ss;
85
	socklen_t	 sslen;
86
	int		 fd = -1, rc, ourfd, erc = EXIT_FAILURE;
87
	uint64_t	 magic;
88
	uint32_t	 cookie, test;
89
	struct pollfd	 pfd[2];
90
	char		 buf[BUFSIZ];
91
	ssize_t		 ssz;
92
	enum kcgi_err	 kerr;
93
	uint16_t	 rid, rtest;
94

95
	ourfd = fdaccept == -1 ? fdfiled : fdaccept;
96
	assert(ourfd != -1);
97

98
	if (kxsocketprep(ourfd) != KCGI_OK)
99
		goto out;
100

101
	for (;;) {
102
		pfd[0].fd = ourfd;
103
		pfd[0].events = POLLIN;
104
		pfd[0].revents = 0;
105
		pfd[1].fd = ctrl;
106
		pfd[1].events = POLLIN;
107
		pfd[1].revents = 0;
108

109
		/*
110
		 * If either the worker or manager disconnect, then exit
111
		 * cleanly.
112
		 * The calling application will check the worker's exit
113
		 * code, which will say whether it did something bad, so
114
		 * we don't really care.
115
		 */
116

117
		if ((rc = poll(pfd, 2, INFTIM)) < 0) {
118
			kutil_warn(NULL, NULL, "poll");
119
			goto out;
120
		} else if (rc == 0) {
121
			kutil_warnx(NULL, NULL, "poll: timeout!?");
122
			continue;
123
		} 
124

125
		if ((pfd[1].revents & POLLHUP) || 
126
		    !(pfd[0].revents & POLLIN))
127
			break;
128

129
		/* 
130
		 * Accept a new connection.
131
		 * In the old way, a blocking accept from FastCGI
132
		 * socket.
133
		 * This will be round-robined by the kernel so that
134
		 * other control processes are fairly notified.
135
		 * In the new one, accepting a descriptor from the
136
		 * caller.
137
		 */
138

139
		if (fdaccept != -1) {
140
			assert(fdfiled == -1);
141
			sslen = sizeof(ss);
142
			fd = accept(fdaccept, 
143
				(struct sockaddr *)&ss, &sslen);
144
			if (fd < 0) {
145
				if (errno == EAGAIN || 
146
				    errno == EWOULDBLOCK)
147
					continue;
148
				kutil_warn(NULL, NULL, "accept");
149
				goto out;
150
			} 
151
		} else {
152
			assert(fdfiled != -1);
153
			rc = fullreadfd(fdfiled, 
154
				&fd, &magic, sizeof(uint64_t));
155
			if (rc < 0)
156
				goto out;
157
			else if (rc == 0)
158
				break;
159
		}
160
		
161
		/* 
162
		 * We then set that the FastCGI socket is non-blocking,
163
		 * making it consistent with the behaviour of the CGI
164
		 * socket, which is also set as such.
165
		 */
166

167
		if (kxsocketprep(fd) != KCGI_OK)
168
			goto out;
169

170
		/* This doesn't need to be crypto quality. */
171

172
#if HAVE_ARC4RANDOM
173
		cookie = arc4random();
174
#else
175
		cookie = random();
176
#endif
177

178
		/* Write a header cookie to the work. */
179

180
		fullwrite(work, &cookie, sizeof(uint32_t));
181

182
		/*
183
		 * Keep pushing data into the worker til it has read it
184
		 * all, at which point it will write to us.
185
		 * If at any point we have errors (e.g., the connection
186
		 * closes), then write a zero-length frame.
187
		 * Write a zero-length frame at the end anyway.
188
		 */
189

190
		pfd[0].fd = fd;
191
		pfd[0].events = POLLIN;
192
		pfd[1].fd = work;
193
		pfd[1].events = POLLIN;
194

195
		for (;;) {
196
			if ((rc = poll(pfd, 2, INFTIM)) < 0) {
197
				kutil_warn(NULL, NULL, "poll");
198
				goto out;
199
			} else if (rc == 0) {
200
				kutil_warnx(NULL, NULL, "poll: timeout!?");
201
				continue;
202
			}
203

204
			/*
205
			 * If the child responds, that means that the
206
			 * full request has been read and processed.
207
			 * If not, we probably still have data to write
208
			 * to it from the connection.
209
			 */
210

211
			if (pfd[1].revents & POLLIN) {
212
				ssz = 0;
213
				kerr = fullwritenoerr
214
					(pfd[1].fd, &ssz, sizeof(size_t));
215
				if (kerr != KCGI_OK)
216
					goto out;
217
				break;
218
			}
219

220
			if (!(pfd[0].revents & POLLIN)) {
221
				kutil_warnx(NULL, NULL, "poll: no input");
222
				goto out;
223
			} else if ((ssz = read(fd, buf, BUFSIZ)) < 0) {
224
				kutil_warn(NULL, NULL, "read");
225
				goto out;
226
			} 
227

228
			/* 
229
			 * Send the child the amount of data we've read.
230
			 * This will let the child see if the connection
231
			 * abruptly closes, at which point we'll have a
232
			 * read size of zero, and error out.
233
			 */
234

235
			kerr = fullwritenoerr
236
				(pfd[1].fd, &ssz, sizeof(size_t));
237
			if (KCGI_OK != kerr)
238
				goto out;
239

240
			kerr = fullwritenoerr(pfd[1].fd, buf, ssz);
241
			if (KCGI_OK != kerr)
242
				goto out;
243

244
			/*
245
			 * If we wrote a zero-sized buffer, it means
246
			 * that the connection has unexpectedly closed.
247
			 * The child will stop all processing for the
248
			 * request and will not return to the parsing
249
			 * routine for the given session.
250
			 */
251

252
			if (ssz == 0) {
253
				kutil_warnx(NULL, NULL, "read: "
254
					"connection closed");
255
				break;
256
			}
257
		}
258

259
		/* Now verify that the worker is sane. */
260

261
		if (fullread(pfd[1].fd, &rc,
262
		    sizeof(int), 0, &kerr) < 0)
263
			goto out;
264

265
		if (rc == 0) {
266
			kutil_warnx(NULL, NULL, "FastCGI: bad code");
267
			goto recover;
268
		}
269

270
		/*
271
		 * We have a non-zero return code.
272
		 * Check our cookie and responseId values.
273
		 */
274

275
		if (fullread(pfd[1].fd, &test,
276
		    sizeof(uint32_t), 0, &kerr) < 0)
277
			goto out;
278

279
		if (cookie != test) {
280
			kutil_warnx(NULL, NULL, "FastCGI: bad cookie");
281
			goto out;
282
		} 
283

284
		if (fullread(pfd[1].fd, &rid, 
285
		    sizeof(uint16_t), 0, &kerr) < 0)
286
			goto out;
287

288
		/*
289
		 * Pass the file descriptor, which has had its data
290
		 * sucked dry, to the main application.
291
		 * It will do output, so it also needs the FastCGI
292
		 * socket request identifier.
293
		 */
294

295
		if (!fullwritefd(ctrl, fd, &rid, sizeof(uint16_t)))
296
			goto out;
297

298
		/* 
299
		 * This will wait til the application is finished.
300
		 * It will then double-check the requestId. 
301
		 */
302

303
		if (fullread(ctrl, &rtest, 
304
		    sizeof(uint16_t), 0, &kerr) < 0)
305
			goto out;
306

307
		if (rid != rtest) {
308
			kutil_warnx(NULL, NULL, "FastCGI: bad cookie");
309
			goto out;
310
		}
311

312
recover:
313
		/*
314
		 * If we are being passed descriptors (instead of
315
		 * waiting on the accept()), then notify the manager
316
		 * that we've finished processing this request.
317
		 * We also jump to here if the connection fails in any
318
		 * way whilst being transcribed to the worker.
319
		 */
320

321
		if (fdfiled != -1) {
322
			kerr = fullwritenoerr(fdfiled, 
323
				&magic, sizeof(uint64_t));
324
			if (KCGI_OK != kerr)
325
				goto out;
326
		}
327

328
		close(fd);
329
		fd = -1;
330
	}
331

332
	erc = EXIT_SUCCESS;
333
out:
334
	if (fd != -1)
335
		close(fd);
336
	close(ourfd);
337
	return erc;
338
}
339

340
void
341
khttp_fcgi_child_free(struct kfcgi *fcgi)
342
{
343

344
	close(fcgi->sock_ctl);
345
	close(fcgi->work_dat);
346
	free(fcgi);
347
}
348

349
enum kcgi_err
350
khttp_fcgi_free(struct kfcgi *fcgi)
351
{
352

353
	if (fcgi == NULL)
354
		return KCGI_OK;
355

356
	close(fcgi->sock_ctl);
357
	close(fcgi->work_dat);
358
	kxwaitpid(fcgi->work_pid);
359
	kxwaitpid(fcgi->sock_pid);
360
	free(fcgi);
361
	return KCGI_OK;
362
}
363

364
enum kcgi_err
365
khttp_fcgi_initx(struct kfcgi **fcgip, 
366
	const char *const *mimes, size_t mimesz,
367
	const struct kvalid *keys, size_t keysz, 
368
	const struct kmimemap *mimemap, size_t defmime,
369
	const char *const *pages, size_t pagesz,
370
	size_t defpage, void *arg, void (*argfree)(void *),
371
	unsigned int debugging, const struct kopts *opts)
372
{
373
	struct kfcgi	*fcgi;
374
	int 		 er, fdaccept, fdfiled;
375
	int		 work_ctl[2], work_dat[2], sock_ctl[2];
376
	pid_t		 work_pid, sock_pid;
377
	const char	*cp, *ercp;
378
	sigset_t	 mask;
379
	enum sandtype	 st;
380

381
	/*
382
	 * Determine whether we're supposed to accept() on a socket or,
383
	 * rather, we're supposed to receive file descriptors from a
384
	 * kfcgi-like manager.
385
	 */
386

387
	st = SAND_CONTROL_OLD;
388
	fdaccept = fdfiled = -1;
389

390
	if ((cp = getenv("FCGI_LISTENSOCK_DESCRIPTORS")) != NULL) {
391
		fdfiled = strtonum(cp, 0, INT_MAX, &ercp);
392
		if (ercp != NULL) {
393
			fdaccept = STDIN_FILENO;
394
			fdfiled = -1;
395
		} else
396
			st = SAND_CONTROL_NEW;
397
	} else
398
		fdaccept = STDIN_FILENO;
399

400
	/*
401
	 * Block this signal unless we're right at the fullreadfd
402
	 * function, at which point unblock and let it interrupt us.
403
	 * We don't save the signal mask because we're allowed free
404
	 * reign on the SIGTERM value.
405
	 */
406

407
	if (signal(SIGTERM, dosignal) == SIG_ERR) {
408
		kutil_warn(NULL, NULL, "signal");
409
		return KCGI_SYSTEM;
410
	}
411

412
	sigemptyset(&mask);
413
	sigaddset(&mask, SIGTERM);
414
	sigprocmask(SIG_BLOCK, &mask, NULL);
415
	sig = 0;
416

417
	if (kxsocketpair(work_ctl) != KCGI_OK)
418
		return KCGI_SYSTEM;
419

420
	if (kxsocketpair(work_dat) != KCGI_OK) {
421
		close(work_ctl[KWORKER_PARENT]);
422
		close(work_ctl[KWORKER_CHILD]);
423
		return KCGI_SYSTEM;
424
	}
425

426
	if ((work_pid = fork()) == -1) {
427
		er = errno;
428
		kutil_warn(NULL, NULL, "fork");
429
		close(work_ctl[KWORKER_PARENT]);
430
		close(work_ctl[KWORKER_CHILD]);
431
		close(work_dat[KWORKER_PARENT]);
432
		close(work_dat[KWORKER_CHILD]);
433
		return (er == EAGAIN) ? KCGI_EAGAIN : KCGI_ENOMEM;
434
	} else if (work_pid == 0) {
435
		if (signal(SIGTERM, SIG_IGN) == SIG_ERR) {
436
			kutil_warn(NULL, NULL, "signal");
437
			_exit(EXIT_FAILURE);
438
		}
439

440
		if (argfree != NULL)
441
			argfree(arg);
442

443
		/* 
444
		 * STDIN_FILENO isn't really stdin, it's the control
445
		 * socket used to pass input sockets to us.
446
		 * Thus, close the parent's control socket. 
447
		 */
448

449
		if (fdaccept != -1)
450
			close(fdaccept);
451
		if (fdfiled != -1)
452
			close(fdfiled);
453

454
		close(STDOUT_FILENO);
455
		close(work_dat[KWORKER_PARENT]);
456
		close(work_ctl[KWORKER_PARENT]);
457

458
		/*
459
		 * Prep child sandbox and run worker process.
460
		 * The worker code will exit on failure, so no need to
461
		 * check any return codes on it.
462
		 */
463

464
		er = EXIT_SUCCESS;
465
		if (!ksandbox_init_child(SAND_WORKER, 
466
		    work_dat[KWORKER_CHILD], 
467
		    work_ctl[KWORKER_CHILD], -1, -1))
468
			er = EXIT_FAILURE;
469
		else
470
			kworker_fcgi_child
471
				(work_dat[KWORKER_CHILD],
472
				 work_ctl[KWORKER_CHILD],
473
				 keys, keysz, mimes, mimesz,
474
				 debugging);
475

476
		close(work_dat[KWORKER_CHILD]);
477
		close(work_ctl[KWORKER_CHILD]);
478
		_exit(er);
479
		/* NOTREACHED */
480
	}
481

482
	close(work_dat[KWORKER_CHILD]);
483
	close(work_ctl[KWORKER_CHILD]);
484

485
	if (kxsocketpair(sock_ctl) != KCGI_OK) {
486
		close(work_dat[KWORKER_PARENT]);
487
		close(work_ctl[KWORKER_PARENT]);
488
		kxwaitpid(work_pid);
489
		return KCGI_SYSTEM;
490
	}
491

492
	if ((sock_pid = fork()) == -1) {
493
		er = errno;
494
		kutil_warn(NULL, NULL, "fork");
495
		close(work_dat[KWORKER_PARENT]);
496
		close(work_ctl[KWORKER_PARENT]);
497
		close(sock_ctl[KWORKER_CHILD]);
498
		close(sock_ctl[KWORKER_PARENT]);
499
		kxwaitpid(work_pid);
500
		return (er == EAGAIN) ? KCGI_EAGAIN : KCGI_ENOMEM;
501
	} else if (sock_pid == 0) {
502
		if (signal(SIGTERM, SIG_IGN) == SIG_ERR) {
503
			kutil_warn(NULL, NULL, "signal");
504
			_exit(EXIT_FAILURE);
505
		}
506

507
		if (argfree != NULL)
508
			argfree(arg);
509

510
		close(STDOUT_FILENO);
511
		close(work_dat[KWORKER_PARENT]);
512
		close(sock_ctl[KWORKER_PARENT]);
513

514
		if (!ksandbox_init_child(st, 
515
		    sock_ctl[KWORKER_CHILD], -1, fdfiled, fdaccept))
516
			er = EXIT_FAILURE;
517
		else 
518
			er = kfcgi_control
519
				(work_ctl[KWORKER_PARENT], 
520
				 sock_ctl[KWORKER_CHILD],
521
				 fdaccept, fdfiled, work_pid);
522

523
		close(work_ctl[KWORKER_PARENT]);
524
		close(sock_ctl[KWORKER_CHILD]);
525
		_exit(er);
526
		/* NOTREACHED */
527
	}
528

529
	close(sock_ctl[KWORKER_CHILD]);
530
	close(work_ctl[KWORKER_PARENT]);
531

532
	if (fdaccept != -1)
533
		close(fdaccept);
534
	if (fdfiled != -1)
535
		close(fdfiled);
536

537
	/* Now allocate our device. */
538

539
	*fcgip = fcgi = kxcalloc(1, sizeof(struct kfcgi));
540
	if (fcgi == NULL) {
541
		close(sock_ctl[KWORKER_PARENT]);
542
		close(work_dat[KWORKER_PARENT]);
543
		kxwaitpid(work_pid);
544
		kxwaitpid(sock_pid);
545
		return KCGI_ENOMEM;
546
	}
547

548
	if (opts == NULL)
549
		fcgi->opts.sndbufsz = -1;
550
	else
551
		memcpy(&fcgi->opts, opts, sizeof(struct kopts));
552

553
	if (fcgi->opts.sndbufsz < 0)
554
		fcgi->opts.sndbufsz = UINT16_MAX;
555

556
	fcgi->work_pid = work_pid;
557
	fcgi->work_dat = work_dat[KWORKER_PARENT];
558
	fcgi->sock_pid = sock_pid;
559
	fcgi->sock_ctl = sock_ctl[KWORKER_PARENT];
560
	fcgi->arg = arg;
561
	fcgi->mimes = mimes;
562
	fcgi->mimesz = mimesz;
563
	fcgi->defmime = defmime;
564
	fcgi->keys = keys;
565
	fcgi->keysz = keysz;
566
	fcgi->mimemap = mimemap;
567
	fcgi->pages = pages;
568
	fcgi->pagesz = pagesz;
569
	fcgi->defpage = defpage;
570
	fcgi->debugging = debugging;
571
	return KCGI_OK;
572
}
573

574
enum kcgi_err
575
khttp_fcgi_init(struct kfcgi **fcgi, 
576
	const struct kvalid *keys, size_t keysz,
577
	const char *const *pages, size_t pagesz,
578
	size_t defpage)
579
{
580

581
	return khttp_fcgi_initx(fcgi, kmimetypes, 
582
		KMIME__MAX, keys, keysz, ksuffixmap,
583
		KMIME_TEXT_HTML, pages, pagesz, defpage, 
584
		NULL, NULL, 0, NULL);
585
}
586

587
/*
588
 * Here we wait for the next FastCGI connection in such a way that, if
589
 * we're notified that we must exit via a SIGTERM, we'll properly close
590
 * down without spurious warnings.
591
 */
592
static enum kcgi_err 
593
fcgi_waitread(int fd)
594
{
595
	int		 rc;
596
	struct pollfd	 pfd;
597
	sigset_t	 mask;
598

599
again:
600
	pfd.fd = fd;
601
	pfd.events = POLLIN;
602

603
	/* 
604
	 * Unblock SIGTERM around the poll().
605
	 * XXX: this could be drastically simplified with ppoll(), but
606
	 * it's not available on many systems.
607
	 * TODO: provide a shim in wrappers.c.
608
	 */
609

610
	sigemptyset(&mask);
611
	sigaddset(&mask, SIGTERM);
612
	sigprocmask(SIG_UNBLOCK, &mask, NULL);
613
	rc = poll(&pfd, 1, 1000);
614
	sigprocmask(SIG_BLOCK, &mask, NULL);
615

616
	/* Exit signal has been set. */
617

618
	if (sig)
619
		return KCGI_EXIT;
620

621
	/* Problems?  Exit.  Timeout?  Retry. */
622

623
	if (rc < 0) {
624
		kutil_warn(NULL, NULL, "poll");
625
		return KCGI_SYSTEM;
626
	} else if (rc == 0) 
627
		goto again;
628

629
	/* Only POLLIN is a "good" exit from this. */
630

631
	if (pfd.revents & POLLIN)
632
		return KCGI_OK;
633
	else if (pfd.revents & POLLHUP)
634
		return KCGI_EXIT;
635

636
	kutil_warnx(NULL, NULL, "poll: error");
637
	return KCGI_SYSTEM;
638
}
639

640
int
641
khttp_fcgi_getfd(const struct kfcgi *fcgi)
642
{
643
	return fcgi->sock_ctl;
644
}
645

646
enum kcgi_err
647
khttp_fcgi_parse(struct kfcgi *fcgi, struct kreq *req)
648
{
649
	enum kcgi_err	 kerr;
650
	const struct kmimemap *mm;
651
	int		 c, fd = -1;
652
	uint16_t	 rid;
653

654
	memset(req, 0, sizeof(struct kreq));
655

656
	/*
657
	 * Blocking wait until our control process sends us the file
658
	 * descriptor and requestId of the current sequence.
659
	 * It may also decide to exit, which we note by seeing that
660
	 * "sig" has been set (inheriting the SIGTERM) or the channel
661
	 * closed gracefully.
662
	 */
663
	
664
	if ((kerr = fcgi_waitread(fcgi->sock_ctl)) != KCGI_OK)
665
		return kerr;
666

667
	c = fullreadfd(fcgi->sock_ctl, &fd, &rid, sizeof(uint16_t));
668
	if (c < 0)
669
		return KCGI_SYSTEM;
670
	else if (c == 0)
671
		return KCGI_EXIT;
672

673
	/* Now get ready to receive data from the child. */
674

675
	req->arg = fcgi->arg;
676
	req->keys = fcgi->keys;
677
	req->keysz = fcgi->keysz;
678
	req->kdata = kdata_alloc(fcgi->sock_ctl, 
679
		fd, rid, fcgi->debugging, &fcgi->opts);
680

681
	if (req->kdata == NULL) {
682
		close(fd);
683
		goto err;
684
	}
685

686
	if (fcgi->keysz) {
687
		req->cookiemap = kxcalloc
688
			(fcgi->keysz, sizeof(struct kpair *));
689
		if (req->cookiemap == NULL)
690
			goto err;
691
		req->cookienmap = kxcalloc
692
			(fcgi->keysz, sizeof(struct kpair *));
693
		if (req->cookienmap == NULL)
694
			goto err;
695
		req->fieldmap = kxcalloc
696
			(fcgi->keysz, sizeof(struct kpair *));
697
		if (req->fieldmap == NULL)
698
			goto err;
699
		req->fieldnmap = kxcalloc
700
			(fcgi->keysz, sizeof(struct kpair *));
701
		if (req->fieldnmap == NULL)
702
			goto err;
703
	}
704

705
	/*
706
	 * Read the request itself from the worker child.
707
	 * We'll wait perpetually on data until the channel closes or
708
	 * until we're interrupted during a read by the parent.
709
	 */
710

711
	kerr = kworker_parent(fcgi->work_dat, req, 0, fcgi->mimesz);
712
	if (KCGI_OK != kerr)
713
		goto err;
714

715
	/* Look up page type from component. */
716

717
	req->page = fcgi->defpage;
718
	if (*req->pagename != '\0')
719
		for (req->page = 0; req->page < fcgi->pagesz; req->page++)
720
			if (strcasecmp(fcgi->pages[req->page], req->pagename) == 0)
721
				break;
722

723
	/* Start with the default. */
724

725
	req->mime = fcgi->defmime;
726
	if (*req->suffix != '\0') {
727
		for (mm = fcgi->mimemap; NULL != mm->name; mm++)
728
			if (strcasecmp(mm->name, req->suffix) == 0) {
729
				req->mime = mm->mime;
730
				break;
731
			}
732
		 /* Could not find this mime type! */
733
		if (mm->name == NULL)
734
			req->mime = fcgi->mimesz;
735
	}
736

737
	return kerr;
738
err:
739
	kdata_free(req->kdata, 0);
740
	req->kdata = NULL;
741
	kreq_free(req);
742
	return kerr;
743
}
744

745
int
746
khttp_fcgi_test(void)
747
{
748
	socklen_t	 len = 0;
749
	const char	*cp, *ercp = NULL;
750

751
	if ((cp = getenv("FCGI_LISTENSOCK_DESCRIPTORS")) != NULL) {
752
		strtonum(cp, 0, INT_MAX, &ercp);
753
		if (ercp == NULL) 
754
			return 1;
755
	} 
756

757
	if (getpeername(STDIN_FILENO, NULL, &len) != -1)
758
		return 0;
759
	return errno == ENOTCONN;
760
}
761

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

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

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

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