Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <httpd.h>
4
 
5
static	char	hstates[] = "nrewE";
6
static	char	hxfers[] = " x";
7
static int _hflush(Hio*, int, int);
8
 
9
int
10
hinit(Hio *h, int fd, int mode)
11
{
12
	if(fd == -1 || mode != Hread && mode != Hwrite)
13
		return -1;
14
	h->hh = nil;
15
	h->fd = fd;
16
	h->seek = 0;
17
	h->state = mode;
18
	h->start = h->buf + 16;		/* leave space for chunk length */
19
	h->stop = h->pos = h->start;
20
	if(mode == Hread){
21
		h->bodylen = ~0UL;
22
		*h->pos = '\0';
23
	}else
24
		h->stop = h->start + Hsize;
25
	return 0;
26
}
27
 
28
int
29
hiserror(Hio *h)
30
{
31
	return h->state == Herr;
32
}
33
 
34
int
35
hgetc(Hio *h)
36
{
37
	uchar *p;
38
 
39
	p = h->pos;
40
	if(p < h->stop){
41
		h->pos = p + 1;
42
		return *p;
43
	}
44
	p -= UTFmax;
45
	if(p < h->start)
46
		p = h->start;
47
	if(!hreadbuf(h, p) || h->pos == h->stop)
48
		return -1;
49
	return *h->pos++;
50
}
51
 
52
int
53
hungetc(Hio *h)
54
{
55
	if(h->state == Hend)
56
		h->state = Hread;
57
	else if(h->state == Hread)
58
		h->pos--;
59
	if(h->pos < h->start || h->state != Hread){
60
		h->state = Herr;
61
		h->pos = h->stop;
62
		return -1;
63
	}
64
	return 0;
65
}
66
 
67
/*
68
 * fill the buffer, saving contents from vsave onwards.
69
 * nothing is saved if vsave is nil.
70
 * returns the beginning of the buffer.
71
 *
72
 * understands message body sizes and chunked transfer encoding
73
 */
74
void *
75
hreadbuf(Hio *h, void *vsave)
76
{
77
	Hio *hh;
78
	uchar *save;
79
	int c, in, cpy, dpos;
80
 
81
	save = vsave;
82
	if(save && (save < h->start || save > h->stop)
83
	|| h->state != Hread && h->state != Hend){
84
		h->state = Herr;
85
		h->pos = h->stop;
86
		return nil;
87
	}
88
 
89
	dpos = 0;
90
	if(save && h->pos > save)
91
		dpos = h->pos - save;
92
	cpy = 0;
93
	if(save){
94
		cpy = h->stop - save;
95
		memmove(h->start, save, cpy);
96
	}
97
	h->seek += h->stop - h->start - cpy;
98
	h->pos = h->start + dpos;
99
 
100
	in = Hsize - cpy;
101
	if(h->state == Hend)
102
		in = 0;
103
	else if(in > h->bodylen)
104
		in = h->bodylen;
105
 
106
	/*
107
	 * for chunked encoding, fill buffer,
108
	 * then read in new chunk length and wipe out that line
109
	 */
110
	hh = h->hh;
111
	if(hh != nil){
112
		if(!in && h->xferenc && h->state != Hend){
113
			if(h->xferenc == 2){
114
				c = hgetc(hh);
115
				if(c == '\r')
116
					c = hgetc(hh);
117
				if(c != '\n'){
118
					h->pos = h->stop;
119
					h->state = Herr;
120
					return nil;
121
				}
122
			}
123
			h->xferenc = 2;
124
			in = 0;
125
			while((c = hgetc(hh)) != '\n'){
126
				if(c >= '0' && c <= '9')
127
					c -= '0';
128
				else if(c >= 'a' && c <= 'f')
129
					c -= 'a' - 10;
130
				else if(c >= 'A' && c <= 'F')
131
					c -= 'A' - 10;
132
				else
133
					break;
134
				in = in * 16 + c;
135
			}
136
			while(c != '\n'){
137
				if(c < 0){
138
					h->pos = h->stop;
139
					h->state = Herr;
140
					return nil;
141
				}
142
				c = hgetc(hh);
143
			}
144
			h->bodylen = in;
145
 
146
			in = Hsize - cpy;
147
			if(in > h->bodylen)
148
				in = h->bodylen;
149
		}
150
		if(in){
151
			while(hh->pos + in > hh->stop){
152
				if(hreadbuf(hh, hh->pos) == nil){
153
					h->pos = h->stop;
154
					h->state = Herr;
155
					return nil;
156
				}
157
			}
158
			memmove(h->start + cpy, hh->pos, in);
159
			hh->pos += in;
160
		}
161
	}else if(in){
162
		if((in = read(h->fd, h->start + cpy, in)) < 0){
163
			h->state = Herr;
164
			h->pos = h->stop;
165
			return nil;
166
		}
167
	}
168
	if(in == 0)
169
		h->state = Hend;
170
 
171
	h->bodylen -= in;
172
 
173
	h->stop = h->start + cpy + in;
174
	*h->stop = '\0';
175
	if(h->pos == h->stop)
176
		return nil;
177
	return h->start;
178
}
179
 
180
int
181
hbuflen(Hio *h, void *p)
182
{
183
	return h->stop - (uchar*)p;
184
}
185
 
186
/*
187
 * prepare to receive a message body
188
 * len is the content length (~0 => unspecified)
189
 * te is the transfer encoding
190
 * returns < 0 if setup failed
191
 */
192
Hio*
193
hbodypush(Hio *hh, ulong len, HFields *te)
194
{
195
	Hio *h;
196
	int xe;
197
 
198
	if(hh->state != Hread)
199
		return nil;
200
	xe = 0;
201
	if(te != nil){
202
		if(te->params != nil || te->next != nil)
203
			return nil;
204
		if(cistrcmp(te->s, "chunked") == 0){
205
			xe = 1;
206
			len = 0;
207
		}else if(cistrcmp(te->s, "identity") == 0){
208
			;
209
		}else
210
			return nil;
211
	}
212
 
213
	h = malloc(sizeof *h);
214
	if(h == nil)
215
		return nil;
216
 
217
	h->hh = hh;
218
	h->fd = -1;
219
	h->seek = 0;
220
	h->state = Hread;
221
	h->xferenc = xe;
222
	h->start = h->buf + 16;		/* leave space for chunk length */
223
	h->stop = h->pos = h->start;
224
	*h->pos = '\0';
225
	h->bodylen = len;
226
	return h;
227
}
228
 
229
/*
230
 * dump the state of the io buffer into a string
231
 */
232
char *
233
hunload(Hio *h)
234
{
235
	uchar *p, *t, *stop, *buf;
236
	int ne, n, c;
237
 
238
	stop = h->stop;
239
	ne = 0;
240
	for(p = h->pos; p < stop; p++){
241
		c = *p;
242
		if(c == 0x80)
243
			ne++;
244
	}
245
	p = h->pos;
246
 
247
	n = (stop - p) + ne + 3;
248
	buf = mallocz(n, 1);
249
	if(buf == nil)
250
		return nil;
251
	buf[0] = hstates[h->state];
252
	buf[1] = hxfers[h->xferenc];
253
 
254
	t = &buf[2];
255
	for(; p < stop; p++){
256
		c = *p;
257
		if(c == 0 || c == 0x80){
258
			*t++ = 0x80;
259
			if(c == 0x80)
260
				*t++ = 0x80;
261
		}else
262
			*t++ = c;
263
	}
264
	*t++ = '\0';
265
	if(t != buf + n)
266
		return nil;
267
	return (char*)buf;
268
}
269
 
270
/*
271
 * read the io buffer state from a string
272
 */
273
int
274
hload(Hio *h, char *buf)
275
{
276
	uchar *p, *t, *stop;
277
	char *s;
278
	int c;
279
 
280
	s = strchr(hstates, buf[0]);
281
	if(s == nil)
282
		return -1;
283
	h->state = s - hstates;
284
 
285
	s = strchr(hxfers, buf[1]);
286
	if(s == nil)
287
		return -1;
288
	h->xferenc = s - hxfers;
289
 
290
	t = h->start;
291
	stop = t + Hsize;
292
	for(p = (uchar*)&buf[2]; c = *p; p++){
293
		if(c == 0x80){
294
			if(p[1] != 0x80)
295
				c = 0;
296
			else
297
				p++;
298
		}
299
		*t++ = c;
300
		if(t >= stop)
301
			return -1;
302
	}
303
	*t = '\0';
304
	h->pos = h->start;
305
	h->stop = t;
306
	h->seek = 0;
307
	return 0;
308
}
309
 
310
void
311
hclose(Hio *h)
312
{
313
	if(h->fd >= 0){
314
		if(h->state == Hwrite)
315
			hxferenc(h, 0);
316
		close(h->fd);
317
	}
318
	h->stop = h->pos = nil;
319
	h->fd = -1;
320
}
321
 
322
/*
323
 * flush the buffer and possibly change encoding modes
324
 */
325
int
326
hxferenc(Hio *h, int on)
327
{
328
	if(h->xferenc && !on && h->pos != h->start)
329
		hflush(h);
330
	if(_hflush(h, 1, 0) < 0)
331
		return -1;
332
	h->xferenc = !!on;
333
	return 0;
334
}
335
 
336
int
337
hputc(Hio *h, int c)
338
{
339
	uchar *p;
340
 
341
	p = h->pos;
342
	if(p < h->stop){
343
		h->pos = p + 1;
344
		return *p = c;
345
	}
346
	if(hflush(h) < 0)
347
		return -1;
348
	return *h->pos++ = c;
349
}
350
 
351
static int
352
fmthflush(Fmt *f)
353
{
354
	Hio *h;
355
 
356
	h = f->farg;
357
	h->pos = f->to;
358
	if(hflush(h) < 0)
359
		return 0;
360
	f->stop = h->stop;
361
	f->to = h->pos;
362
	f->start = h->pos;
363
	return 1;
364
}
365
 
366
int
367
hvprint(Hio *h, char *fmt, va_list args)
368
{
369
	int n;
370
	Fmt f;
371
 
372
	f.runes = 0;
373
	f.stop = h->stop;
374
	f.to = h->pos;
375
	f.start = h->pos;
376
	f.flush = fmthflush;
377
	f.farg = h;
378
	f.nfmt = 0;
379
//	fmtlocaleinit(&f, nil, nil, nil);
380
	n = fmtvprint(&f, fmt, args);
381
	h->pos = f.to;
382
	return n;
383
}
384
 
385
int
386
hprint(Hio *h, char *fmt, ...)
387
{
388
	int n;
389
	va_list arg;
390
 
391
	va_start(arg, fmt);
392
	n = hvprint(h, fmt, arg);
393
	va_end(arg);
394
	return n;
395
}
396
 
397
static int
398
_hflush(Hio *h, int force, int dolength)
399
{
400
	uchar *s;
401
	int w;
402
 
403
	if(h == nil)
404
		return -1;
405
	if(h->state != Hwrite){
406
		h->state = Herr;
407
		h->stop = h->pos;
408
		return -1;
409
	}
410
	s = h->start;
411
	w = h->pos - s;
412
	if(w == 0 && !force)
413
		return 0;
414
	if(h->xferenc){
415
		*--s = '\n';
416
		*--s = '\r';
417
		do{
418
			*--s = "0123456789abcdef"[w & 0xf];
419
			w >>= 4;
420
		}while(w);
421
		h->pos[0] = '\r';
422
		h->pos[1] = '\n';
423
		w = &h->pos[2] - s;
424
	}
425
	if(dolength)
426
		fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
427
	if(write(h->fd, s, w) != w){
428
		h->state = Herr;
429
		h->stop = h->pos;
430
		return -1;
431
	}
432
	h->seek += w;
433
	h->pos = h->start;
434
	return 0;
435
}
436
 
437
int
438
hflush(Hio *h)
439
{
440
	return _hflush(h, 0, 0);
441
}
442
 
443
int
444
hlflush(Hio* h)
445
{
446
	return _hflush(h, 0, 1);
447
}
448
 
449
int
450
hwrite(Hio *h, void *vbuf, int len)
451
{
452
	uchar *buf;
453
	int n, m;
454
 
455
	buf = vbuf;
456
	n = len;
457
	if(n < 0 || h->state != Hwrite){
458
		h->state = Herr;
459
		h->stop = h->pos;
460
		return -1;
461
	}
462
	if(h->pos + n >= h->stop){
463
		if(h->start != h->pos)
464
			if(hflush(h) < 0)
465
				return -1;
466
		while(h->pos + n >= h->stop){
467
			m = h->stop - h->pos;
468
			if(h->xferenc){
469
				memmove(h->pos, buf, m);
470
				h->pos += m;
471
				if(hflush(h) < 0)
472
					return -1;
473
			}else{
474
				if(write(h->fd, buf, m) != m){
475
					h->state = Herr;
476
					h->stop = h->pos;
477
					return -1;
478
				}
479
				h->seek += m;
480
			}
481
			n -= m;
482
			buf += m;
483
		}
484
	}
485
	memmove(h->pos, buf, n);
486
	h->pos += n;
487
	return len;
488
}