| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#define FCGI_BEGIN_REQUEST 1 |
|
2
|
|
|
|
|
|
|
#define FCGI_ABORT_REQUEST 2 |
|
3
|
|
|
|
|
|
|
#define FCGI_END_REQUEST 3 |
|
4
|
|
|
|
|
|
|
#define FCGI_PARAMS 4 |
|
5
|
|
|
|
|
|
|
#define FCGI_STDIN 5 |
|
6
|
|
|
|
|
|
|
#define FCGI_STDOUT 6 |
|
7
|
|
|
|
|
|
|
#define FCGI_STDERR 7 |
|
8
|
|
|
|
|
|
|
#define FCGI_DATA 8 |
|
9
|
|
|
|
|
|
|
#define FCGI_GET_VALUES 9 |
|
10
|
|
|
|
|
|
|
#define FCGI_GET_VALUES_RESULT 10 |
|
11
|
|
|
|
|
|
|
#define FCGI_UNKNOWN_TYPE 11 |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#define FUFE_OK 0 |
|
14
|
|
|
|
|
|
|
#define FUFE_EOF -1 /* unexpected protocol-level EOF */ |
|
15
|
|
|
|
|
|
|
#define FUFE_IO -2 |
|
16
|
|
|
|
|
|
|
#define FUFE_PROTO -3 |
|
17
|
|
|
|
|
|
|
#define FUFE_PLEN -4 |
|
18
|
|
|
|
|
|
|
#define FUFE_CLEN -5 |
|
19
|
|
|
|
|
|
|
#define FUFE_ABORT -6 /* explicit abort or client-level EOF */ |
|
20
|
|
|
|
|
|
|
#define FUFE_NOREQ -7 /* protocol-level EOF before we received anything */ |
|
21
|
|
|
|
|
|
|
#define FUFE_SEND -8 /* error in send() */ |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#define FUFCGI_MAX_DATA 65535 |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
typedef struct { |
|
26
|
|
|
|
|
|
|
SV *self; |
|
27
|
|
|
|
|
|
|
int fd; |
|
28
|
|
|
|
|
|
|
int maxproc; |
|
29
|
|
|
|
|
|
|
int keepconn; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
int reqid; |
|
32
|
|
|
|
|
|
|
HV *headers; |
|
33
|
|
|
|
|
|
|
HV *params; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
/* Single buffer for reading & writing, we only do one thing at a time */ |
|
36
|
|
|
|
|
|
|
char buf[8 + FUFCGI_MAX_DATA + 255]; /* fits a maximum-length fcgi record */ |
|
37
|
|
|
|
|
|
|
int len; /* total number of bytes in the buffer */ |
|
38
|
|
|
|
|
|
|
int off; /* number of bytes consumed */ |
|
39
|
|
|
|
|
|
|
} fufcgi; |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
typedef struct { |
|
42
|
|
|
|
|
|
|
unsigned char type; |
|
43
|
|
|
|
|
|
|
unsigned short id; |
|
44
|
|
|
|
|
|
|
int len; |
|
45
|
|
|
|
|
|
|
char *data; |
|
46
|
|
|
|
|
|
|
} fufcgi_rec; |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
/* Incremental param length & name parser */ |
|
50
|
|
|
|
|
|
|
typedef enum { |
|
51
|
|
|
|
|
|
|
FUFC_INIT, FUFC_L1, FUFC_L2, FUFC_L3, |
|
52
|
|
|
|
|
|
|
FUFC_V0, FUFC_V1, FUFC_V2, FUFC_V3, |
|
53
|
|
|
|
|
|
|
FUFC_N0, FUFC_NX |
|
54
|
|
|
|
|
|
|
} fufcgi_paramstate; |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
typedef struct { |
|
57
|
|
|
|
|
|
|
int namelen; |
|
58
|
|
|
|
|
|
|
int vallen; |
|
59
|
|
|
|
|
|
|
int state; |
|
60
|
|
|
|
|
|
|
int namerd; |
|
61
|
|
|
|
|
|
|
char *name; |
|
62
|
|
|
|
|
|
|
char namebuf[128]; /* We don't support longer param names */ |
|
63
|
|
|
|
|
|
|
} fufcgi_param; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
/* Returns NULL on error or ptr to value (or 'end' if !done) */ |
|
66
|
95
|
|
|
|
|
|
static char *fufcgi_param_parse(fufcgi_param *p, char *buf, char *end) { |
|
67
|
384
|
100
|
|
|
|
|
while (buf < end) { |
|
68
|
357
|
|
|
|
|
|
switch (p->state) { |
|
69
|
77
|
|
|
|
|
|
case FUFC_INIT: |
|
70
|
77
|
|
|
|
|
|
p->vallen = p->namerd = 0; |
|
71
|
77
|
100
|
|
|
|
|
if (*buf & 0x80) { |
|
72
|
6
|
|
|
|
|
|
p->namelen = (*buf & 0x1f) << 24; |
|
73
|
6
|
|
|
|
|
|
p->state = FUFC_L1; |
|
74
|
|
|
|
|
|
|
} else { |
|
75
|
71
|
|
|
|
|
|
p->namelen = *buf; |
|
76
|
71
|
|
|
|
|
|
p->state = FUFC_V0; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
77
|
|
|
|
|
|
break; |
|
79
|
6
|
|
|
|
|
|
case FUFC_L1: |
|
80
|
6
|
|
|
|
|
|
p->namelen |= ((unsigned char)*buf) << 16; |
|
81
|
6
|
|
|
|
|
|
p->state = FUFC_L2; |
|
82
|
6
|
|
|
|
|
|
break; |
|
83
|
6
|
|
|
|
|
|
case FUFC_L2: |
|
84
|
6
|
|
|
|
|
|
p->namelen |= ((unsigned char)*buf) << 8; |
|
85
|
6
|
|
|
|
|
|
p->state = FUFC_L3; |
|
86
|
6
|
|
|
|
|
|
break; |
|
87
|
6
|
|
|
|
|
|
case FUFC_L3: |
|
88
|
6
|
|
|
|
|
|
p->namelen |= (unsigned char)*buf; |
|
89
|
6
|
|
|
|
|
|
p->state = FUFC_V0; |
|
90
|
6
|
100
|
|
|
|
|
if (p->namelen > (int)sizeof(p->namebuf)) return NULL; |
|
91
|
3
|
|
|
|
|
|
break; |
|
92
|
74
|
|
|
|
|
|
case FUFC_V0: |
|
93
|
74
|
100
|
|
|
|
|
if (*buf & 0x80) { |
|
94
|
6
|
|
|
|
|
|
p->vallen = (*buf & 0x1f) << 24; |
|
95
|
6
|
|
|
|
|
|
p->state = FUFC_V1; |
|
96
|
|
|
|
|
|
|
} else { |
|
97
|
68
|
|
|
|
|
|
p->vallen = *buf; |
|
98
|
68
|
100
|
|
|
|
|
p->state = p->namelen ? FUFC_N0 : FUFC_INIT; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
74
|
|
|
|
|
|
break; |
|
101
|
6
|
|
|
|
|
|
case FUFC_V1: |
|
102
|
6
|
|
|
|
|
|
p->vallen |= ((unsigned char)*buf) << 16; |
|
103
|
6
|
100
|
|
|
|
|
if (p->vallen) return NULL; /* Let's just disallow param values > 64 KiB */ |
|
104
|
3
|
|
|
|
|
|
p->state = FUFC_V2; |
|
105
|
3
|
|
|
|
|
|
break; |
|
106
|
3
|
|
|
|
|
|
case FUFC_V2: |
|
107
|
3
|
|
|
|
|
|
p->vallen |= ((unsigned char)*buf) << 8; |
|
108
|
3
|
|
|
|
|
|
p->state = FUFC_V3; |
|
109
|
3
|
|
|
|
|
|
break; |
|
110
|
3
|
|
|
|
|
|
case FUFC_V3: |
|
111
|
3
|
|
|
|
|
|
p->vallen |= (unsigned char)*buf; |
|
112
|
3
|
|
|
|
|
|
p->state = FUFC_N0; |
|
113
|
3
|
|
|
|
|
|
break; |
|
114
|
65
|
|
|
|
|
|
case FUFC_N0: |
|
115
|
65
|
100
|
|
|
|
|
if (p->namelen <= end - buf) { |
|
116
|
56
|
|
|
|
|
|
p->name = buf; |
|
117
|
56
|
|
|
|
|
|
p->state = FUFC_INIT; |
|
118
|
56
|
|
|
|
|
|
return buf + p->namelen; |
|
119
|
|
|
|
|
|
|
} else { |
|
120
|
9
|
|
|
|
|
|
p->name = p->namebuf; |
|
121
|
9
|
|
|
|
|
|
p->name[0] = *buf; |
|
122
|
9
|
|
|
|
|
|
p->namerd = 1; |
|
123
|
9
|
|
|
|
|
|
p->state = FUFC_NX; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
9
|
|
|
|
|
|
break; |
|
126
|
111
|
|
|
|
|
|
case FUFC_NX: |
|
127
|
111
|
|
|
|
|
|
p->name[p->namerd++] = *buf; |
|
128
|
111
|
100
|
|
|
|
|
if (p->namerd == p->namelen) { |
|
129
|
6
|
|
|
|
|
|
p->state = FUFC_INIT; |
|
130
|
6
|
|
|
|
|
|
return buf + 1; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
105
|
|
|
|
|
|
break; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
289
|
|
|
|
|
|
buf++; |
|
135
|
|
|
|
|
|
|
} |
|
136
|
27
|
|
|
|
|
|
return buf; |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
447
|
|
|
|
|
|
static int fufcgi_fill(fufcgi *ctx, int len) { |
|
140
|
447
|
100
|
|
|
|
|
if ((int)sizeof(ctx->buf) - ctx->off < len) { |
|
141
|
4
|
|
|
|
|
|
memmove(ctx->buf, ctx->buf+ctx->off, ctx->len - ctx->off); |
|
142
|
4
|
|
|
|
|
|
ctx->len -= ctx->off; |
|
143
|
4
|
|
|
|
|
|
ctx->off = 0; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
506
|
100
|
|
|
|
|
while (ctx->len - ctx->off < len) { |
|
146
|
65
|
|
|
|
|
|
ssize_t r = read(ctx->fd, ctx->buf+ctx->len, sizeof(ctx->buf) - ctx->len); |
|
147
|
65
|
100
|
|
|
|
|
if (r <= 0) return r == 0 ? FUFE_EOF : FUFE_IO; |
|
|
|
50
|
|
|
|
|
|
|
148
|
59
|
|
|
|
|
|
ctx->len += r; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
441
|
|
|
|
|
|
return FUFE_OK; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
228
|
|
|
|
|
|
static int fufcgi_read_record(fufcgi *ctx, fufcgi_rec *rec) { |
|
154
|
|
|
|
|
|
|
int r; |
|
155
|
228
|
100
|
|
|
|
|
if ((r = fufcgi_fill(ctx, 8)) != FUFE_OK) return r; |
|
156
|
|
|
|
|
|
|
|
|
157
|
222
|
100
|
|
|
|
|
if (ctx->buf[ctx->off] != 1) return FUFE_PROTO; /* version */ |
|
158
|
219
|
|
|
|
|
|
rec->type = ctx->buf[ctx->off+1]; |
|
159
|
219
|
|
|
|
|
|
rec->id = fu_frombeU(16, ctx->buf+ctx->off+2); |
|
160
|
219
|
|
|
|
|
|
rec->len = fu_frombeU(16, ctx->buf+ctx->off+4); |
|
161
|
219
|
|
|
|
|
|
int pad = (unsigned char)ctx->buf[ctx->off+6]; |
|
162
|
219
|
|
|
|
|
|
ctx->off += 8; |
|
163
|
|
|
|
|
|
|
|
|
164
|
219
|
50
|
|
|
|
|
if ((r = fufcgi_fill(ctx, rec->len + pad)) != FUFE_OK) return r; |
|
165
|
219
|
|
|
|
|
|
rec->data = ctx->buf + ctx->off; |
|
166
|
219
|
|
|
|
|
|
ctx->off += rec->len + pad; |
|
167
|
219
|
|
|
|
|
|
return FUFE_OK; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
/* Unbuffered write of a single record, first 8 bytes of 'buf' are filled out |
|
171
|
|
|
|
|
|
|
* by this function, record contents must come after. */ |
|
172
|
31
|
|
|
|
|
|
static int fufcgi_write_record(fufcgi *ctx, fufcgi_rec *hdr, char *buf) { |
|
173
|
31
|
|
|
|
|
|
buf[0] = 1; |
|
174
|
31
|
|
|
|
|
|
buf[1] = hdr->type; |
|
175
|
31
|
|
|
|
|
|
fu_tobeU(16, buf+2, hdr->id); |
|
176
|
31
|
|
|
|
|
|
fu_tobeU(16, buf+4, hdr->len); |
|
177
|
31
|
|
|
|
|
|
buf[6] = 0; |
|
178
|
31
|
|
|
|
|
|
buf[7] = 0; |
|
179
|
31
|
|
|
|
|
|
int len = hdr->len + 8; |
|
180
|
56
|
100
|
|
|
|
|
while (len > 0) { |
|
181
|
31
|
|
|
|
|
|
int r = send(ctx->fd, buf, len, MSG_NOSIGNAL); |
|
182
|
31
|
100
|
|
|
|
|
if (r <= 0) return FUFE_SEND; |
|
183
|
25
|
|
|
|
|
|
buf += r; |
|
184
|
25
|
|
|
|
|
|
len -= r; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
25
|
|
|
|
|
|
return FUFE_OK; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
3
|
|
|
|
|
|
static int fufcgi_handle_values(fufcgi *ctx, fufcgi_rec *rec, char *buf) { |
|
190
|
3
|
|
|
|
|
|
int reslen = 8; |
|
191
|
3
|
|
|
|
|
|
char *param = rec->data; |
|
192
|
3
|
|
|
|
|
|
char *end = rec->data + rec->len; |
|
193
|
|
|
|
|
|
|
fufcgi_param p; |
|
194
|
3
|
|
|
|
|
|
p.state = FUFC_INIT; |
|
195
|
|
|
|
|
|
|
|
|
196
|
15
|
100
|
|
|
|
|
while (param < end) { |
|
197
|
12
|
50
|
|
|
|
|
if ((param = fufcgi_param_parse(&p, param, end)) == NULL) return FUFE_PLEN; |
|
198
|
12
|
50
|
|
|
|
|
if (p.state != FUFC_INIT) return FUFE_PROTO; |
|
199
|
12
|
50
|
|
|
|
|
if (p.vallen > end - param) return FUFE_PROTO; |
|
200
|
12
|
50
|
|
|
|
|
if (reslen >= 100) return FUFE_PROTO; /* implies requested params were duplicated */ |
|
201
|
|
|
|
|
|
|
|
|
202
|
12
|
100
|
|
|
|
|
if (p.namelen == 14 && memcmp(p.name, "FCGI_MAX_CONNS", 14) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
203
|
3
|
|
|
|
|
|
memcpy(buf+reslen, "\x0e\0FCGI_MAX_CONNS", 16); |
|
204
|
3
|
|
|
|
|
|
int l = sprintf(buf+reslen+16, "%d", ctx->maxproc); |
|
205
|
3
|
|
|
|
|
|
buf[reslen+1] = l; |
|
206
|
3
|
|
|
|
|
|
reslen += 16 + l; |
|
207
|
|
|
|
|
|
|
|
|
208
|
9
|
100
|
|
|
|
|
} else if (p.namelen == 13 && memcmp(p.name, "FCGI_MAX_REQS", 13) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
209
|
3
|
|
|
|
|
|
memcpy(buf+reslen, "\x0d\0FCGI_MAX_REQS", 15); |
|
210
|
3
|
|
|
|
|
|
int l = sprintf(buf+reslen+15, "%d", ctx->maxproc); |
|
211
|
3
|
|
|
|
|
|
buf[reslen+1] = l; |
|
212
|
3
|
|
|
|
|
|
reslen += 15 + l; |
|
213
|
|
|
|
|
|
|
|
|
214
|
6
|
100
|
|
|
|
|
} else if (p.namelen == 15 && memcmp(p.name, "FCGI_MPXS_CONNS", 15) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
215
|
3
|
|
|
|
|
|
memcpy(buf+reslen, "\x0f\1FCGI_MPXS_CONNS0", 18); |
|
216
|
3
|
|
|
|
|
|
reslen += 18; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
12
|
|
|
|
|
|
param += p.vallen; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
3
|
|
|
|
|
|
rec->type = FCGI_GET_VALUES_RESULT; |
|
222
|
3
|
|
|
|
|
|
rec->len = reslen - 8; |
|
223
|
3
|
|
|
|
|
|
return fufcgi_write_record(ctx, rec, buf); |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
/* Read a PARAMS/STDIN/ABORT record corresponding to the current id, starts |
|
227
|
|
|
|
|
|
|
* reading a new request if id=0. */ |
|
228
|
169
|
|
|
|
|
|
static int fufcgi_read_req_record(fufcgi *ctx, fufcgi_rec *rec) { |
|
229
|
|
|
|
|
|
|
int r; |
|
230
|
|
|
|
|
|
|
char tmp[128]; /* Large enough for a FCGI_GET_VALUES_RESULT */ |
|
231
|
|
|
|
|
|
|
while (1) { |
|
232
|
228
|
100
|
|
|
|
|
if ((r = fufcgi_read_record(ctx, rec)) != FUFE_OK) return r == FUFE_EOF && ctx->len == 0 ? FUFE_NOREQ : r; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
|
|
234
|
219
|
|
|
|
|
|
switch (rec->type) { |
|
235
|
157
|
|
|
|
|
|
case FCGI_PARAMS: |
|
236
|
|
|
|
|
|
|
case FCGI_STDIN: |
|
237
|
|
|
|
|
|
|
case FCGI_ABORT_REQUEST: |
|
238
|
157
|
50
|
|
|
|
|
if (rec->id != ctx->reqid) return FUFE_PROTO; |
|
239
|
157
|
|
|
|
|
|
return FUFE_OK; |
|
240
|
56
|
|
|
|
|
|
case FCGI_BEGIN_REQUEST: |
|
241
|
56
|
50
|
|
|
|
|
if (!rec->id || rec->id == ctx->reqid) return FUFE_PROTO; |
|
|
|
50
|
|
|
|
|
|
|
242
|
56
|
50
|
|
|
|
|
if (rec->len != 8) return FUFE_PROTO; |
|
243
|
56
|
|
|
|
|
|
ctx->keepconn = rec->data[2] & 1; |
|
244
|
56
|
50
|
|
|
|
|
if (rec->data[0] != 0 || rec->data[1] != 1) { /* FCGI_RESPONDER */ |
|
|
|
100
|
|
|
|
|
|
|
245
|
6
|
|
|
|
|
|
memcpy(tmp+8, "\0\0\0\0\3\0\0\0", 8); /* FCGI_UNKNOWN_ROLE */ |
|
246
|
6
|
|
|
|
|
|
rec->type = FCGI_END_REQUEST; |
|
247
|
6
|
|
|
|
|
|
rec->len = 8; |
|
248
|
6
|
100
|
|
|
|
|
if ((r = fufcgi_write_record(ctx, rec, tmp)) != FUFE_OK) return r; |
|
249
|
3
|
50
|
|
|
|
|
if (!ctx->keepconn) return FUFE_EOF; |
|
250
|
50
|
100
|
|
|
|
|
} else if (ctx->reqid) { |
|
251
|
3
|
|
|
|
|
|
memcpy(tmp+8, "\0\0\0\0\1\0\0\0", 8); /* FCGI_CANT_MPX_CONN */ |
|
252
|
3
|
|
|
|
|
|
rec->type = FCGI_END_REQUEST; |
|
253
|
3
|
|
|
|
|
|
rec->len = 8; |
|
254
|
3
|
50
|
|
|
|
|
if ((r = fufcgi_write_record(ctx, rec, tmp)) != FUFE_OK) return r; |
|
255
|
3
|
50
|
|
|
|
|
if (!ctx->keepconn) return FUFE_EOF; |
|
256
|
|
|
|
|
|
|
} else { |
|
257
|
47
|
|
|
|
|
|
ctx->reqid = rec->id; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
53
|
|
|
|
|
|
break; |
|
260
|
3
|
|
|
|
|
|
case FCGI_GET_VALUES: |
|
261
|
3
|
50
|
|
|
|
|
if (rec->id) return FUFE_PROTO; |
|
262
|
3
|
50
|
|
|
|
|
if ((r = fufcgi_handle_values(ctx, rec, tmp)) != FUFE_OK) return r; |
|
263
|
3
|
|
|
|
|
|
break; |
|
264
|
3
|
|
|
|
|
|
default: |
|
265
|
3
|
|
|
|
|
|
memset(tmp+8, 0, 8); |
|
266
|
3
|
|
|
|
|
|
tmp[8] = rec->type; |
|
267
|
3
|
|
|
|
|
|
rec->type = FCGI_UNKNOWN_TYPE; |
|
268
|
3
|
|
|
|
|
|
rec->len = 8; |
|
269
|
3
|
|
|
|
|
|
rec->id = 0; |
|
270
|
3
|
50
|
|
|
|
|
if ((r = fufcgi_write_record(ctx, rec, tmp)) != FUFE_OK) return r; |
|
271
|
3
|
|
|
|
|
|
break; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
56
|
|
|
|
|
|
static int fufcgi_read_params(pTHX_ fufcgi *ctx, fufcgi_rec *rec) { |
|
277
|
|
|
|
|
|
|
int r; |
|
278
|
|
|
|
|
|
|
fufcgi_param p; |
|
279
|
56
|
|
|
|
|
|
p.state = FUFC_INIT; |
|
280
|
|
|
|
|
|
|
|
|
281
|
56
|
|
|
|
|
|
SV *valsv = NULL; |
|
282
|
56
|
|
|
|
|
|
char *val = NULL; |
|
283
|
56
|
|
|
|
|
|
int valleft = 0; |
|
284
|
|
|
|
|
|
|
|
|
285
|
68
|
|
|
|
|
|
while (1) { |
|
286
|
124
|
100
|
|
|
|
|
if ((r = fufcgi_read_req_record(ctx, rec)) != FUFE_OK) return r; |
|
287
|
112
|
100
|
|
|
|
|
if (rec->type == FCGI_ABORT_REQUEST) return FUFE_OK; |
|
288
|
109
|
100
|
|
|
|
|
if (rec->type != FCGI_PARAMS) return FUFE_PROTO; |
|
289
|
106
|
100
|
|
|
|
|
if (rec->len == 0) return p.state != FUFC_INIT || valleft ? FUFE_PROTO : FUFE_OK; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
|
|
291
|
74
|
|
|
|
|
|
char *buf = rec->data; |
|
292
|
74
|
|
|
|
|
|
char *end = rec->data + rec->len; |
|
293
|
177
|
100
|
|
|
|
|
while (buf < end) { |
|
294
|
133
|
100
|
|
|
|
|
if (valleft) { |
|
295
|
50
|
|
|
|
|
|
r = valleft > end - buf ? end - buf : valleft; |
|
296
|
50
|
100
|
|
|
|
|
if (val) { |
|
297
|
41
|
|
|
|
|
|
memcpy(val, buf, r); |
|
298
|
41
|
|
|
|
|
|
val += r; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
50
|
|
|
|
|
|
valleft -= r; |
|
301
|
50
|
|
|
|
|
|
buf += r; |
|
302
|
50
|
100
|
|
|
|
|
if (val && !valleft) { |
|
|
|
100
|
|
|
|
|
|
|
303
|
35
|
|
|
|
|
|
*val = 0; |
|
304
|
35
|
|
|
|
|
|
SvCUR_set(valsv, p.vallen); |
|
305
|
|
|
|
|
|
|
} |
|
306
|
50
|
|
|
|
|
|
continue; |
|
307
|
|
|
|
|
|
|
} |
|
308
|
83
|
100
|
|
|
|
|
if ((buf = fufcgi_param_parse(&p, buf, end)) == NULL) return FUFE_PLEN; |
|
309
|
77
|
100
|
|
|
|
|
if (p.state != FUFC_INIT) break; |
|
310
|
|
|
|
|
|
|
|
|
311
|
53
|
|
|
|
|
|
valsv = NULL; |
|
312
|
53
|
|
|
|
|
|
val = NULL; |
|
313
|
53
|
|
|
|
|
|
valleft = p.vallen; |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
/* https://www.rfc-editor.org/rfc/rfc3875 */ |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
/* Request header */ |
|
318
|
53
|
100
|
|
|
|
|
if (p.namelen > 5 && memcmp(p.name, "HTTP_", 5) == 0) { |
|
|
|
100
|
|
|
|
|
|
|
319
|
12
|
|
|
|
|
|
p.namelen -= 5; |
|
320
|
12
|
|
|
|
|
|
p.name += 5; |
|
321
|
111
|
100
|
|
|
|
|
for (r=0; r
|
|
322
|
99
|
100
|
|
|
|
|
p.name[r] = p.name[r] == '_' ? '-' : p.name[r] >= 'A' && p.name[r] <= 'Z' ? p.name[r] | 0x20 : p.name[r]; |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
323
|
12
|
100
|
|
|
|
|
if (!(p.namelen == 14 && memcmp(p.name, "content-length", 14) == 0) |
|
|
|
50
|
|
|
|
|
|
|
324
|
6
|
50
|
|
|
|
|
&& !(p.namelen == 12 && memcmp(p.name, "content-type", 12) == 0)) { |
|
|
|
0
|
|
|
|
|
|
|
325
|
6
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
326
|
6
|
|
|
|
|
|
hv_store(ctx->headers, p.name, p.namelen, valsv, 0); |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
41
|
100
|
|
|
|
|
} else if (p.namelen == 14 && memcmp(p.name, "CONTENT_LENGTH", 14) == 0) { |
|
|
|
100
|
|
|
|
|
|
|
330
|
17
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
331
|
17
|
|
|
|
|
|
hv_stores(ctx->headers, "content-length", valsv); |
|
332
|
|
|
|
|
|
|
|
|
333
|
24
|
100
|
|
|
|
|
} else if (p.namelen == 12 && memcmp(p.name, "CONTENT_TYPE", 12) == 0) { |
|
|
|
100
|
|
|
|
|
|
|
334
|
6
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
335
|
6
|
|
|
|
|
|
hv_stores(ctx->headers, "content-type", valsv); |
|
336
|
|
|
|
|
|
|
|
|
337
|
18
|
100
|
|
|
|
|
} else if (p.namelen == 11 && memcmp(p.name, "REMOTE_ADDR", 11) == 0) { |
|
|
|
100
|
|
|
|
|
|
|
338
|
3
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
339
|
3
|
|
|
|
|
|
hv_stores(ctx->params, "ip", valsv); |
|
340
|
|
|
|
|
|
|
|
|
341
|
15
|
100
|
|
|
|
|
} else if (p.namelen == 12 && memcmp(p.name, "QUERY_STRING", 12) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
342
|
3
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
343
|
3
|
|
|
|
|
|
hv_stores(ctx->params, "qs", valsv); |
|
344
|
|
|
|
|
|
|
|
|
345
|
12
|
100
|
|
|
|
|
} else if (p.namelen == 14 && memcmp(p.name, "REQUEST_METHOD", 14) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
346
|
3
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
347
|
3
|
|
|
|
|
|
hv_stores(ctx->params, "method", valsv); |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
/* Not in rfc3875; there's no standardized parameter for the URI, |
|
350
|
|
|
|
|
|
|
* but every FastCGI-capable web server includes this one */ |
|
351
|
9
|
100
|
|
|
|
|
} else if (p.namelen == 11 && memcmp(p.name, "REQUEST_URI", 11) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
352
|
3
|
|
|
|
|
|
valsv = newSV(p.vallen+1); |
|
353
|
3
|
|
|
|
|
|
hv_stores(ctx->params, "path", valsv); |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
} else { /* ignore */ } |
|
356
|
|
|
|
|
|
|
|
|
357
|
53
|
100
|
|
|
|
|
if (valsv) { |
|
358
|
41
|
|
|
|
|
|
SvPOK_only(valsv); |
|
359
|
41
|
|
|
|
|
|
val = SvPVX(valsv); |
|
360
|
41
|
|
|
|
|
|
*val = 0; /* in case vallen = 0 */ |
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
} |
|
365
|
|
|
|
|
|
|
|
|
366
|
56
|
|
|
|
|
|
static int fufcgi_read_req(pTHX_ fufcgi *ctx, SV *headers, SV *params) { |
|
367
|
56
|
50
|
|
|
|
|
if (ctx->reqid) fu_confess("Invalid attempt to read FastCGI request before finishing the previous one"); |
|
368
|
|
|
|
|
|
|
fufcgi_rec rec; |
|
369
|
|
|
|
|
|
|
int r; |
|
370
|
|
|
|
|
|
|
|
|
371
|
56
|
|
|
|
|
|
ctx->off = ctx->len = 0; |
|
372
|
56
|
|
|
|
|
|
ctx->headers = (HV *)SvRV(headers); |
|
373
|
56
|
|
|
|
|
|
ctx->params = (HV *)SvRV(params); |
|
374
|
56
|
100
|
|
|
|
|
if ((r = fufcgi_read_params(aTHX_ ctx, &rec)) != FUFE_OK) return r; |
|
375
|
|
|
|
|
|
|
|
|
376
|
29
|
|
|
|
|
|
int stdinlen = 0; |
|
377
|
29
|
|
|
|
|
|
SV **contentlength = hv_fetchs(ctx->headers, "content-length", 0); |
|
378
|
29
|
100
|
|
|
|
|
if (contentlength && *contentlength) { |
|
|
|
50
|
|
|
|
|
|
|
379
|
17
|
|
|
|
|
|
UV uv = 0; |
|
380
|
17
|
|
|
|
|
|
char *v = SvPV_nolen(*contentlength); |
|
381
|
17
|
100
|
|
|
|
|
if (*v && !grok_atoUV(v, &uv, NULL)) return FUFE_CLEN; |
|
|
|
50
|
|
|
|
|
|
|
382
|
17
|
50
|
|
|
|
|
if (uv >= INT_MAX) return FUFE_CLEN; |
|
383
|
17
|
|
|
|
|
|
stdinlen = uv; |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
|
|
386
|
29
|
|
|
|
|
|
SV *sv = newSV(stdinlen+1); |
|
387
|
29
|
|
|
|
|
|
hv_stores(ctx->params, "body", sv); |
|
388
|
29
|
|
|
|
|
|
SvPOK_only(sv); |
|
389
|
29
|
|
|
|
|
|
char *stdinbuf = SvPVX(sv); |
|
390
|
29
|
|
|
|
|
|
int stdinleft = stdinlen; |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
while (1) { |
|
393
|
74
|
100
|
|
|
|
|
if (rec.type == FCGI_ABORT_REQUEST) return FUFE_ABORT; |
|
394
|
71
|
100
|
|
|
|
|
else if (rec.type == FCGI_PARAMS) { |
|
395
|
26
|
50
|
|
|
|
|
if (rec.len != 0) return FUFE_PROTO; |
|
396
|
45
|
50
|
|
|
|
|
} else if (rec.type == FCGI_STDIN) { |
|
397
|
45
|
100
|
|
|
|
|
if (rec.len == 0) { |
|
398
|
26
|
|
|
|
|
|
*stdinbuf = 0; |
|
399
|
26
|
|
|
|
|
|
SvCUR_set(sv, stdinlen - stdinleft); |
|
400
|
26
|
100
|
|
|
|
|
return stdinleft == 0 ? FUFE_OK : FUFE_ABORT; |
|
401
|
|
|
|
|
|
|
} |
|
402
|
19
|
50
|
|
|
|
|
if (rec.len > stdinleft) return FUFE_PROTO; |
|
403
|
19
|
|
|
|
|
|
memcpy(stdinbuf, rec.data, rec.len); |
|
404
|
19
|
|
|
|
|
|
stdinbuf += rec.len; |
|
405
|
19
|
|
|
|
|
|
stdinleft -= rec.len; |
|
406
|
|
|
|
|
|
|
} else { |
|
407
|
0
|
|
|
|
|
|
return FUFE_PROTO; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
45
|
50
|
|
|
|
|
if ((r = fufcgi_read_req_record(ctx, &rec)) != FUFE_OK) return r; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
} |
|
412
|
|
|
|
|
|
|
|
|
413
|
8
|
|
|
|
|
|
static void fufcgi_flush(pTHX_ fufcgi *ctx) { |
|
414
|
|
|
|
|
|
|
fufcgi_rec hdr; |
|
415
|
8
|
100
|
|
|
|
|
if (ctx->len > 0) { |
|
416
|
5
|
|
|
|
|
|
hdr.len = ctx->len; |
|
417
|
5
|
|
|
|
|
|
hdr.type = FCGI_STDOUT; |
|
418
|
5
|
|
|
|
|
|
hdr.id = ctx->reqid; |
|
419
|
5
|
50
|
|
|
|
|
if (fufcgi_write_record(ctx, &hdr, ctx->buf) != FUFE_OK) |
|
420
|
0
|
|
|
|
|
|
croak("%s\n", strerror(errno)); |
|
421
|
5
|
|
|
|
|
|
ctx->len = 0; |
|
422
|
|
|
|
|
|
|
} |
|
423
|
8
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
11
|
|
|
|
|
|
static void fufcgi_print(pTHX_ fufcgi *ctx, const char *buf, int len) { |
|
426
|
|
|
|
|
|
|
int r; |
|
427
|
23
|
100
|
|
|
|
|
while (len > 0) { |
|
428
|
12
|
|
|
|
|
|
r = len > FUFCGI_MAX_DATA - ctx->len ? FUFCGI_MAX_DATA - ctx->len : len; |
|
429
|
12
|
|
|
|
|
|
memcpy(ctx->buf+8+ctx->len, buf, r); |
|
430
|
12
|
|
|
|
|
|
ctx->len += r; |
|
431
|
12
|
|
|
|
|
|
len -= r; |
|
432
|
12
|
|
|
|
|
|
buf += r; |
|
433
|
12
|
100
|
|
|
|
|
if (ctx->len >= FUFCGI_MAX_DATA) fufcgi_flush(aTHX_ ctx); |
|
434
|
|
|
|
|
|
|
} |
|
435
|
11
|
|
|
|
|
|
} |
|
436
|
|
|
|
|
|
|
|
|
437
|
7
|
|
|
|
|
|
static void fufcgi_done(pTHX_ fufcgi *ctx) { |
|
438
|
|
|
|
|
|
|
fufcgi_rec hdr; |
|
439
|
7
|
|
|
|
|
|
fufcgi_flush(aTHX_ ctx); |
|
440
|
|
|
|
|
|
|
|
|
441
|
7
|
|
|
|
|
|
hdr.len = 0; |
|
442
|
7
|
|
|
|
|
|
hdr.type = FCGI_STDOUT; |
|
443
|
7
|
|
|
|
|
|
hdr.id = ctx->reqid; |
|
444
|
7
|
100
|
|
|
|
|
if (fufcgi_write_record(ctx, &hdr, ctx->buf) != FUFE_OK) |
|
445
|
3
|
|
|
|
|
|
croak("%s\n", strerror(errno)); |
|
446
|
|
|
|
|
|
|
|
|
447
|
4
|
|
|
|
|
|
memcpy(ctx->buf+8, "\0\0\0\0\0\0\0\0", 8); /* FCGI_REQUEST_COMPLETE */ |
|
448
|
4
|
|
|
|
|
|
hdr.type = FCGI_END_REQUEST; |
|
449
|
4
|
|
|
|
|
|
hdr.len = 8; |
|
450
|
4
|
50
|
|
|
|
|
if (fufcgi_write_record(ctx, &hdr, ctx->buf) != FUFE_OK) |
|
451
|
0
|
|
|
|
|
|
croak("%s\n", strerror(errno)); |
|
452
|
|
|
|
|
|
|
|
|
453
|
4
|
|
|
|
|
|
ctx->reqid = ctx->len = ctx->off = 0; |
|
454
|
4
|
|
|
|
|
|
} |