1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "udm_config.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <sys/types.h>
25
26 #include "udm_common.h"
27 #include "udm_socket.h"
28 #include "udm_host.h"
29 #include "udm_utils.h"
30 #include "udm_xmalloc.h"
31 #include "udm_http.h"
32 #include "udm_conf.h"
33 #include "udm_contentencoding.h"
34 #include "udm_url.h"
35 #include "udm_vars.h"
36 #include "udm_hrefs.h"
37 #include "udm_crc32.h"
38
39
40 udm_content_type_t
UdmContentTypeByName(const char * str)41 UdmContentTypeByName(const char *str)
42 {
43 if (!strncasecmp(str, UDM_CSTR_WITH_LEN("text/plain")) ||
44 !strncasecmp(str, UDM_CSTR_WITH_LEN("text/tab-separated-values")) ||
45 !strncasecmp(str, UDM_CSTR_WITH_LEN("text/x-diff")) ||
46 !strncasecmp(str, UDM_CSTR_WITH_LEN("text/x-patch")) ||
47 !strncasecmp(str, UDM_CSTR_WITH_LEN("application/x-patch")) ||
48 !strncasecmp(str, UDM_CSTR_WITH_LEN("text/css")))
49 return UDM_CONTENT_TYPE_TEXT_PLAIN;
50
51 if (!strncasecmp(str,"text/html", 9))
52 return UDM_CONTENT_TYPE_TEXT_HTML;
53
54 /*
55 application/atom+xml
56 text/xml
57 application/xml
58 application/rsd+xml
59 application/rdf+xml
60 application/xml
61 application/opensearchdescription+xml
62 text/xml+rss
63 application/rss+xml
64 text/vnd.wap.wml
65 */
66 if (!strncasecmp(str, UDM_CSTR_WITH_LEN("text/xml")) ||
67 !strncasecmp(str, UDM_CSTR_WITH_LEN("text/vnd.wap.wml")) ||
68 !strncasecmp(str, UDM_CSTR_WITH_LEN("application/xml")) ||
69 strstr(str, "+xml") ||
70 strstr(str, "rss"))
71 return UDM_CONTENT_TYPE_TEXT_XML;
72
73 if (!strncasecmp(str, UDM_CSTR_WITH_LEN("message/rfc822")))
74 return UDM_CONTENT_TYPE_MESSAGE_RFC822;
75
76 if (!strncasecmp(str, "audio/mpeg", 10))
77 return UDM_CONTENT_TYPE_AUDIO_MPEG;
78
79 if (!strncasecmp(str, "mnogosearch/htdb", 16))
80 return UDM_CONTENT_TYPE_HTDB;
81
82 if (!strncasecmp(str, UDM_CSTR_WITH_LEN("application/vnd.openxmlformats-officedocument.wordprocessingml.document")))
83 return UDM_CONTENT_TYPE_DOCX;
84
85 /* Note: text/richtext and text/enriched is not rtf, it's something else */
86 if (!strncasecmp(str, UDM_CSTR_WITH_LEN("text/rtf")) ||
87 !strncasecmp(str, UDM_CSTR_WITH_LEN("application/rtf")) ||
88 !strncasecmp(str, UDM_CSTR_WITH_LEN("application/x-rtf")))
89 return UDM_CONTENT_TYPE_TEXT_RTF;
90
91 return UDM_CONTENT_TYPE_UNKNOWN;
92 }
93
94
95 size_t
UdmHTTPFindContent(const char * src,size_t srclen)96 UdmHTTPFindContent(const char *src, size_t srclen)
97 {
98 const char *src0= src, *srcend= src + srclen;
99 for ( ; src < srcend; src++)
100 {
101 if (*src == '\n' && src + 1 < srcend && src[1] == '\n')
102 return src - src0 + 2;
103 if (*src == '\r' && src + 3 < srcend && !memcmp(src, "\r\n\r\n", 4))
104 return src - src0 + 4;
105 }
106 return 0;
107 }
108
109
110 size_t
UdmHTTPBufFindContent(UDM_HTTPBUF * Buf)111 UdmHTTPBufFindContent(UDM_HTTPBUF *Buf)
112 {
113 char *token;
114 for (token= Buf->buf; *token; token++)
115 {
116 if(!strncmp(token,"\r\n\r\n",4))
117 {
118 Buf->content= token + 4;
119 return token - Buf->buf;
120 break;
121 }
122 else if(!strncmp(token,"\n\n",2))
123 {
124 Buf->content= token + 2;
125 return token - Buf->buf;
126 break;
127 }
128 }
129 return 0;
130 }
131
132
133 static void
UdmSplitContentTypeAndCharset(UDM_VARLIST * Vars,const char * ctname,const char * csname,char * val)134 UdmSplitContentTypeAndCharset(UDM_VARLIST *Vars,
135 const char *ctname,
136 const char *csname, char *val)
137 {
138 char *v;
139 if ((v= strstr(val, "charset=")))
140 {
141 const char *cs;
142 char *semicolon= strchr(v + 8, ';');
143 if (semicolon)
144 *semicolon= '\0';
145 cs= UdmCharsetCanonicalName(v + 8);
146 *v= '\0';
147 UdmRTrim(val, "; ");
148 UdmVarListReplaceStr(Vars, csname, cs ? cs : v + 8);
149 }
150 UdmVarListReplaceStr(Vars, ctname, val);
151 }
152
153
154 /* TODO34: unify with UdmParseHTTPResponse */
155 void
UdmHTTPBufParseHeadersForCachedCopy(UDM_VARLIST * Vars,const char * src,size_t srclen)156 UdmHTTPBufParseHeadersForCachedCopy(UDM_VARLIST *Vars,
157 const char *src, size_t srclen)
158 {
159 char *headers, *token, *lt;
160 udm_bool_t x_orig_content_type_found= UDM_FALSE;
161
162 if (!(headers= (char*) udm_strndup(src, srclen)))
163 return;
164
165 for (token= udm_strtok_r(headers,"\r\n",<) ; token;
166 token= udm_strtok_r(NULL,"\r\n",<))
167 {
168 char *val;
169 if ((val= strchr(token,':')))
170 {
171 char name[128];
172 *val++='\0';
173 val= UdmTrim(val," \t:");
174 udm_snprintf(name, sizeof(name), "Cached.%s", token);
175 if (!strcasecmp(token, "Content-Type") ||
176 !strcasecmp(token, "Content-Encoding") ||
177 !strcasecmp(token, "X-Orig.Content-Type"))
178 {
179 char *v;
180 for(v=val ; *v ; v++)
181 *v= tolower(*v);
182 /* TODO34: UdmNormalizeContenType*/
183 if (!strcasecmp(token, "Content-Type"))
184 UdmSplitContentTypeAndCharset(Vars, name, "Cached.Charset", val);
185 else if (!strcasecmp(token, "X-Orig.Content-Type"))
186 {
187 UdmSplitContentTypeAndCharset(Vars, "Content-Type", "Charset", val);
188 x_orig_content_type_found= UDM_TRUE;
189 }
190 else
191 UdmVarListReplaceStr(Vars, name, val);
192 }
193 else
194 UdmVarListReplaceStr(Vars, name, val);
195 }
196 }
197
198 /*
199 If there was no "X-Orig.Content-Type" header, then copy
200 "Content-Type" and "Charset" from
201 "Cached.Content-Type" and "Cached.Charset",
202 to display in search template.
203 */
204 if (!x_orig_content_type_found)
205 {
206 const char *val;
207 if ((val= UdmVarListFindStr(Vars, "Cached.Content-Type", NULL)))
208 UdmVarListReplaceStr(Vars, "Content-Type", val);
209 if ((val= UdmVarListFindStr(Vars, "Cached.Charset", NULL)))
210 UdmVarListReplaceStr(Vars, "Charset", val);
211 }
212 UdmFree(headers);
213 }
214
215
UdmParseHTTPResponse(UDM_AGENT * Indexer,UDM_DOCUMENT * Doc)216 void UdmParseHTTPResponse(UDM_AGENT * Indexer,UDM_DOCUMENT * Doc){
217 char *token, *lt, *headers;
218 int oldstatus, htdb_content_length= 0;
219 size_t content_offset;
220
221 UdmHTTPBufResetContent(&Doc->Buf);
222 oldstatus = UdmVarListFindInt(&Doc->Sections, "Status", 0);
223 UdmVarListReplaceInt(&Doc->Sections, "ResponseSize", (int) UdmHTTPBufSize(&Doc->Buf));
224 UdmVarListDel(&Doc->Sections, "Content-Length");
225 UdmVarListDel(&Doc->Sections, "Last-Modified");
226
227 /* Cut HTTP response header first */
228 if (!(content_offset= UdmHTTPBufFindContent(&Doc->Buf)))
229 {
230 /* Put content pointer to the very end of the buffer */
231 Doc->Buf.content= Doc->Buf.buf + Doc->Buf.size;
232 return;
233 }
234
235 /* Copy headers not to break them */
236 headers= (char*) udm_strndup(UdmHTTPBufPtr(&Doc->Buf), content_offset);
237
238 /* Now lets parse response header lines */
239 if (!(token = udm_strtok_r(headers,"\r\n",<)))
240 return;
241
242 if(!strncmp(token,"HTTP/",5))
243 {
244 int status = atoi(token + 8);
245 UdmVarListReplaceStr(&Doc->Sections,"ResponseLine",token);
246 UdmVarListReplaceInt(&Doc->Sections, "Status", (oldstatus > status) ? oldstatus : status );
247 }
248 else
249 {
250 return;
251 }
252
253 for (token= udm_strtok_r(NULL,"\r\n",<) ; token;
254 token = udm_strtok_r(NULL,"\r\n",<))
255 {
256 char *val;
257
258 if((val=strchr(token,':')))
259 {
260 *val++='\0';
261 val = UdmTrim(val," \t:");
262
263 if (!strcasecmp(token, "Content-Type") ||
264 !strcasecmp(token, "Content-Encoding"))
265 {
266 char *v;
267 for(v=val ; *v ; v++)
268 *v = tolower(*v);
269 }
270 /*
271 else if (!strcasecmp(token, "HTDB-Content-Length"))
272 {
273 htdb_content_length= atoi(val);
274 }
275 */
276 else if (!strcasecmp(token, "Set-Cookie"))
277 {
278 char fullname[256];
279 char *part, *lpart;
280 char *name= NULL;
281 char *value= NULL;
282 const char *domain= NULL;
283 const char *path= NULL;
284 for (part= udm_strtok_r(val, ";" , &lpart) ; part;
285 part= udm_strtok_r(NULL, ";", &lpart))
286 {
287 char *arg;
288 part= UdmTrim(part, " ");
289 if ((arg= strchr(part, '=')))
290 {
291 *arg++= '\0';
292 if (!name)
293 {
294 name= part;
295 value= arg;
296 continue;
297 }
298 if (!strcasecmp(part, "path"))
299 {
300 path= arg;
301 continue;
302 }
303 if (!strcasecmp(part, "domain"))
304 {
305 domain= arg;
306 continue;
307 }
308 }
309 }
310 if (name && value)
311 {
312 if (domain && domain[0] == '.')
313 {
314 domain++;
315 }
316 else
317 {
318 domain= Doc->CurURL.hostname ? Doc->CurURL.hostname : "localhost";
319 }
320 if (!path)
321 {
322 path= Doc->CurURL.path ? Doc->CurURL.path : "/";
323 }
324 udm_snprintf(fullname, sizeof(fullname), "Set-Cookie.%s@%s%s", name, domain, path);
325 UdmVarListReplaceStr(&Doc->Sections, fullname, value);
326 }
327 continue;
328 }
329 }
330 UdmVarListReplaceStr(&Doc->Sections,token,val?val:"<NULL>");
331 }
332 UDM_FREE(headers);
333
334 UdmVarListInsInt(&Doc->Sections,"Content-Length",
335 UdmHTTPBufContentSize(&Doc->Buf) + htdb_content_length);
336 }
337
338
339 void
UdmHTTPBufInit(UDM_HTTPBUF * Buf)340 UdmHTTPBufInit(UDM_HTTPBUF *Buf)
341 {
342 bzero(Buf, sizeof(*Buf));
343 }
344
345
346 const char*
UdmHTTPBufPtr(const UDM_HTTPBUF * Buf)347 UdmHTTPBufPtr(const UDM_HTTPBUF *Buf)
348 {
349 /*return Buf->buf + header_size;*/
350 return Buf->buf;
351 }
352
353
354 const char*
UdmHTTPBufContent(const UDM_HTTPBUF * Buf)355 UdmHTTPBufContent(const UDM_HTTPBUF *Buf)
356 {
357 /*return Buf->buf + header_size;*/
358 return Buf->content;
359 }
360
361
362 udm_bool_t
UdmHTTPBufContentToConstStr(const UDM_HTTPBUF * Buf,UDM_CONST_STR * str)363 UdmHTTPBufContentToConstStr(const UDM_HTTPBUF *Buf, UDM_CONST_STR *str)
364 {
365 if (!Buf->content)
366 return UDM_TRUE;
367 str->str= UdmHTTPBufContent(Buf);
368 str->length= UdmHTTPBufContentSize(Buf);
369 return UDM_FALSE;
370 }
371
372 void
UdmHTTPBufReset(UDM_HTTPBUF * Buf)373 UdmHTTPBufReset(UDM_HTTPBUF *Buf)
374 {
375 Buf->size= 0;
376 Buf->content= NULL;
377 Buf->buf[0]= '\0';
378 }
379
380
381 size_t
UdmHTTPBufAllocedSize(const UDM_HTTPBUF * Buf)382 UdmHTTPBufAllocedSize(const UDM_HTTPBUF *Buf)
383 {
384 return Buf->alloced_size;
385 }
386
387
388 size_t
UdmHTTPBufAvailableSize(const UDM_HTTPBUF * Buf)389 UdmHTTPBufAvailableSize(const UDM_HTTPBUF *Buf)
390 {
391 UDM_ASSERT(Buf->alloced_size >= Buf->size);
392 return Buf->alloced_size - Buf->size;
393 }
394
395
396 size_t
UdmHTTPBufSize(const UDM_HTTPBUF * Buf)397 UdmHTTPBufSize(const UDM_HTTPBUF *Buf)
398 {
399 return Buf->size;
400 }
401
402
403 size_t
UdmHTTPBufContentSize(const UDM_HTTPBUF * Buf)404 UdmHTTPBufContentSize(const UDM_HTTPBUF *Buf)
405 {
406 return Buf->size - (Buf->content - Buf->buf);
407 }
408
409
410 /*
411 Header size, including trailing "\r\n"
412 */
413 size_t
UdmHTTPBufHeaderSize(const UDM_HTTPBUF * Buf)414 UdmHTTPBufHeaderSize(const UDM_HTTPBUF *Buf)
415 {
416 return Buf->content - Buf->buf;
417 }
418
419
420 udmcrc32_t
UdmHTTPBufCRC32(const UDM_HTTPBUF * Buf)421 UdmHTTPBufCRC32(const UDM_HTTPBUF *Buf)
422 {
423 UDM_CONST_STR content;
424 if (UdmHTTPBufContentToConstStr(Buf, &content))
425 return 0;
426 return UdmCRC32(content.str, content.length);
427 }
428
429
430 /*
431 "dst" must have enough space to store UdmHTTPBufContentSize() bytes.
432 */
433 void
UdmHTTPBufContentExport(const UDM_HTTPBUF * Buf,char * dst)434 UdmHTTPBufContentExport(const UDM_HTTPBUF *Buf, char *dst)
435 {
436 UDM_CONST_STR content;
437 if (UdmHTTPBufContentToConstStr(Buf, &content))
438 return;
439 memcpy(dst, content.str, content.length);
440 }
441
442
443 void
UdmHTTPBufPutContent(UDM_HTTPBUF * Buf,const char * src,size_t len)444 UdmHTTPBufPutContent(UDM_HTTPBUF *Buf, const char *src, size_t len)
445 {
446 size_t available_len= UdmHTTPBufAvailableSize(Buf);
447 if (!available_len)
448 return;
449 available_len--; /* For trailing 0 */
450 if (len > available_len)
451 len= available_len;
452 memcpy(Buf->content, src, len);
453 Buf->size= UdmHTTPBufHeaderSize(Buf) + len;
454 Buf->buf[Buf->size]= '\0';
455 }
456
457
458 void
UdmHTTPBufTruncateContent(UDM_HTTPBUF * Buf)459 UdmHTTPBufTruncateContent(UDM_HTTPBUF *Buf)
460 {
461 Buf->size= UdmHTTPBufHeaderSize(Buf);
462 Buf->buf[Buf->size]= '\0';
463 }
464
465 void
UdmHTTPBufResetContent(UDM_HTTPBUF * Buf)466 UdmHTTPBufResetContent(UDM_HTTPBUF *Buf)
467 {
468 Buf->content= NULL;
469 }
470
471
472 udm_rc_t
UdmHTTPBufAlloc(UDM_HTTPBUF * Buf,size_t size)473 UdmHTTPBufAlloc(UDM_HTTPBUF *Buf, size_t size)
474 {
475 UDM_ASSERT(size > 0 && Buf->alloced_size == 0 && Buf->content == NULL);
476 if (!(Buf->buf= (char*) UdmMalloc(size)))
477 return UDM_ERROR;
478 Buf->alloced_size= size;
479 Buf->buf[0]= '\0';
480 return UDM_OK;
481 }
482
483
484 udm_rc_t
UdmHTTPBufRealloc(UDM_HTTPBUF * Buf,size_t size)485 UdmHTTPBufRealloc(UDM_HTTPBUF *Buf, size_t size)
486 {
487 UDM_ASSERT(size > 0);
488 if (!(Buf->buf= (char*) UdmRealloc(Buf->buf, size)))
489 return UDM_ERROR;
490 Buf->alloced_size= size;
491 return UDM_OK;
492 }
493
494
495 udm_rc_t
UdmHTTPBufShrink(UDM_HTTPBUF * Buf)496 UdmHTTPBufShrink(UDM_HTTPBUF *Buf)
497 {
498 return UdmHTTPBufRealloc(Buf, Buf->size);
499 }
500
501
502 void
UdmHTTPBufFree(UDM_HTTPBUF * Buf)503 UdmHTTPBufFree(UDM_HTTPBUF *Buf)
504 {
505 UDM_FREE(Buf->buf);
506 Buf->content= NULL;
507 Buf->size= 0;
508 Buf->alloced_size= 0;
509 }
510
511
512 static udm_rc_t
UdmHTTPBufAppendVA(UDM_HTTPBUF * Buf,const char * fmt,va_list ap)513 UdmHTTPBufAppendVA(UDM_HTTPBUF *Buf, const char *fmt, va_list ap)
514 {
515 int nc;
516 size_t bytes_left= Buf->alloced_size - Buf->size - 1;
517 UDM_ASSERT(Buf->alloced_size);
518 UDM_ASSERT(Buf->alloced_size > Buf->size);
519
520 if (bytes_left < 2)
521 return UDM_ERROR;
522
523 nc= vsnprintf(Buf->buf + Buf->size, bytes_left, fmt, ap);
524 if (nc > -1 && nc < bytes_left)
525 Buf->size+= nc;
526 Buf->buf[Buf->size]= '\0';
527 return UDM_OK;
528 }
529
530
531 udm_rc_t
UdmHTTPBufPrintf(UDM_HTTPBUF * Buf,const char * fmt,...)532 UdmHTTPBufPrintf(UDM_HTTPBUF *Buf, const char *fmt, ...)
533 {
534 udm_rc_t rc;
535 va_list ap;
536 UdmHTTPBufReset(Buf);
537 va_start(ap, fmt);
538 rc= UdmHTTPBufAppendVA(Buf, fmt, ap);
539 va_end(ap);
540 return rc;
541 }
542
543
544 udm_rc_t
UdmHTTPBufAppendf(UDM_HTTPBUF * Buf,const char * fmt,...)545 UdmHTTPBufAppendf(UDM_HTTPBUF *Buf, const char *fmt, ...)
546 {
547 udm_rc_t rc;
548 va_list ap;
549 va_start(ap, fmt);
550 rc= UdmHTTPBufAppendVA(Buf, fmt, ap);
551 va_end(ap);
552 return rc;
553 }
554
555
556 udm_rc_t
UdmHTTPBufAppendFromFile(UDM_HTTPBUF * Buf,int fd)557 UdmHTTPBufAppendFromFile(UDM_HTTPBUF *Buf, int fd)
558 {
559 ssize_t bytes;
560 /* Note: we need a loop, in case fd is a pipe (e.g. popen) */
561 while ((bytes= read(fd, Buf->buf + Buf->size,
562 Buf->alloced_size - 1 - Buf->size)))
563 {
564 if (bytes == -1)
565 return UDM_ERROR;
566 Buf->size+= bytes;
567 }
568 Buf->buf[Buf->size]= '\0';
569 return UDM_OK;
570 }
571
572 udm_rc_t
UdmHTTPBufAppend(UDM_HTTPBUF * Buf,const char * src,size_t len)573 UdmHTTPBufAppend(UDM_HTTPBUF *Buf, const char *src, size_t len)
574 {
575 size_t bytes_left= Buf->alloced_size - Buf->size - 1;
576 if (bytes_left > 0)
577 {
578 size_t nbytes= UDM_MIN(bytes_left, len);
579 memcpy(Buf->buf + Buf->size, src, nbytes);
580 Buf->size+= nbytes;
581 Buf->buf[Buf->size]= '\0';
582 return UDM_OK;
583 }
584 return UDM_ERROR;
585 }
586
587
588 udm_rc_t
UdmHTTPBufAppendHTTPTime(UDM_HTTPBUF * Buf,time_t tm)589 UdmHTTPBufAppendHTTPTime(UDM_HTTPBUF *Buf, time_t tm)
590 {
591 char str[UDM_MAXTIMESTRLEN];
592 UdmTime_t2HttpStr(tm, str, UDM_MAXTIMESTRLEN);
593 return UdmHTTPBufAppend(Buf, str, strlen(str));
594 }
595
596
597 void
UdmHTTPBufShiftLeft(UDM_HTTPBUF * Buf,size_t offs)598 UdmHTTPBufShiftLeft(UDM_HTTPBUF *Buf, size_t offs)
599 {
600 UDM_ASSERT(offs <= Buf->size);
601 memmove(Buf->buf, Buf->buf + offs, Buf->size - offs);
602 Buf->content= Buf->buf;
603 Buf->size-= offs;
604 Buf->buf[Buf->size]= '\0';
605 }
606
607
608 udm_rc_t
UdmHTTPBufInflate(UDM_HTTPBUF * Buf,const char * src,size_t srclen)609 UdmHTTPBufInflate(UDM_HTTPBUF *Buf, const char *src, size_t srclen)
610 {
611 udm_rc_t rc;
612 Buf->size= UdmInflate(Buf->buf, Buf->alloced_size - 1, src, srclen, &rc);
613 Buf->content= Buf->buf;
614 Buf->buf[Buf->size]= '\0';
615 return rc;
616 }
617
618
619 udm_rc_t
UdmHTTPBufInflateAppend(UDM_HTTPBUF * Buf,const char * src,size_t srclen)620 UdmHTTPBufInflateAppend(UDM_HTTPBUF *Buf, const char *src, size_t srclen)
621 {
622 udm_rc_t rc;
623 size_t dstlen;
624 if (Buf->size + 1 > Buf->alloced_size)
625 return UDM_ERROR;
626 /* TODO34: Check why the old code (in 3.3) had this:
627 if ((content[0] == (char) 0x1f) && (content[1] == (char)0x8b))
628 {
629 memcpy(zstream.next_in, content + 2, csize - 2);
630 // 2 bytes - header, 4 bytes - trailing CRC
631 zstream.avail_in= csize - 6;
632 }
633 else
634 {
635 memcpy(zstream.next_in, UdmHTTPBufContent (&Doc->Buf), csize);
636 zstream.avail_in= csize;
637 }
638 */
639 dstlen= UdmInflate(Buf->buf + Buf->size, Buf->alloced_size - Buf->size - 1,
640 src, srclen, &rc);
641 Buf->size+= dstlen;
642 Buf->buf[Buf->size]= '\0';
643 return rc;
644 }
645
646
647 udm_rc_t
UdmHTTPBufDeflateAppend(UDM_HTTPBUF * Buf,const char * src,size_t srclen)648 UdmHTTPBufDeflateAppend(UDM_HTTPBUF *Buf, const char *src, size_t srclen)
649 {
650 udm_rc_t rc;
651 size_t dstlen;
652 if (Buf->size + 1 > Buf->alloced_size)
653 return UDM_ERROR;
654 dstlen= UdmDeflate(Buf->buf + Buf->size, Buf->alloced_size - Buf->size - 1,
655 src, srclen, &rc);
656 Buf->size+= dstlen;
657 Buf->buf[Buf->size]= '\0';
658 return rc;
659 }
660
661
662 udm_rc_t
UdmHTTPBufUnGzipAppend(UDM_HTTPBUF * Buf,const char * src,size_t srclen)663 UdmHTTPBufUnGzipAppend(UDM_HTTPBUF *Buf, const char *src, size_t srclen)
664 {
665 udm_rc_t rc;
666 size_t dstlen;
667 if (Buf->size + 1 > Buf->alloced_size)
668 return UDM_ERROR;
669 dstlen= UdmUnGzip(Buf->buf + Buf->size, Buf->alloced_size - Buf->size - 1,
670 src, srclen, &rc);
671 Buf->size+= dstlen;
672 Buf->buf[Buf->size]= '\0';
673 return rc;
674 }
675
676
677 udm_rc_t
UdmHTTPBufUncompressAppend(UDM_HTTPBUF * Buf,const char * src,size_t srclen)678 UdmHTTPBufUncompressAppend(UDM_HTTPBUF *Buf, const char *src, size_t srclen)
679 {
680 size_t dstlen;
681 udm_rc_t rc;
682 if (Buf->size + 1 > Buf->alloced_size)
683 return UDM_ERROR;
684 dstlen= UdmUncompress(Buf->buf + Buf->size, Buf->alloced_size - Buf->size - 1,
685 src, srclen, &rc);
686 Buf->size+= dstlen;
687 Buf->buf[Buf->size]= '\0';
688 return rc;
689 }
690
691
692 udm_rc_t
UdmHTTPBufAppendEncodingDecode(UDM_HTTPBUF * Buf,const char * src,size_t length,udm_content_encoding_t encoding)693 UdmHTTPBufAppendEncodingDecode(UDM_HTTPBUF *Buf,
694 const char *src, size_t length,
695 udm_content_encoding_t encoding)
696 {
697 udm_rc_t rc= UDM_OK;
698 switch (encoding)
699 {
700 case UDM_CONTENT_ENCODING_GZIP:
701 rc= UdmHTTPBufUnGzipAppend(Buf, src, length);
702 break;
703 case UDM_CONTENT_ENCODING_DEFLATE:
704 rc= UdmHTTPBufInflateAppend(Buf, src, length);
705 break;
706 case UDM_CONTENT_ENCODING_ZLIB_COMPRESS:
707 rc= UdmHTTPBufUncompressAppend(Buf, src, length);
708 break;
709 case UDM_CONTENT_ENCODING_IDENTITY:
710 UdmHTTPBufAppend(Buf, src, length);
711 rc= UDM_OK;
712 break;
713 case UDM_CONTENT_ENCODING_UNKNOWN:
714 rc= UDM_ERROR;
715 }
716 return rc;
717 }
718
719
720 udm_rc_t
UdmHTTPBufAppendBase64Decode(UDM_HTTPBUF * Buf,const char * src,size_t srclen)721 UdmHTTPBufAppendBase64Decode(UDM_HTTPBUF *Buf,
722 const char *src, size_t srclen)
723 {
724 int res;
725
726 if (UdmHTTPBufAvailableSize(Buf) < srclen + 1 ||
727 (res= UdmBase64Decode(src, srclen, Buf->buf + Buf->size, NULL, 0)) < 0)
728 return UDM_ERROR;
729 Buf->size+= (size_t) res;
730 Buf->buf[Buf->size]= '\0';
731 return UDM_OK;
732 }
733
734
735 udm_rc_t
UdmHTTPBufBase64Decode(UDM_HTTPBUF * Buf,const char * src,size_t len)736 UdmHTTPBufBase64Decode(UDM_HTTPBUF *Buf,
737 const char *src, size_t len)
738 {
739 UdmHTTPBufReset(Buf);
740 Buf->content= Buf->buf; /* No headers */
741 return UdmHTTPBufAppendBase64Decode(Buf, src, len);
742 }
743
744
745 udm_rc_t
UdmHTTPBufAppendQuotedPrintableDecode(UDM_HTTPBUF * Buf,const char * src,size_t srclen)746 UdmHTTPBufAppendQuotedPrintableDecode(UDM_HTTPBUF *Buf,
747 const char *src, size_t srclen)
748 {
749 size_t res, available_size;
750
751 if ((available_size= UdmHTTPBufAvailableSize(Buf)) < srclen + 1)
752 return UDM_ERROR;
753 res= udm_quoted_printable_decode(src, srclen, Buf->buf + Buf->size, available_size);
754 Buf->size+= (size_t) res;
755 Buf->buf[Buf->size]= '\0';
756 return UDM_OK;
757 }
758
759
760 udm_rc_t
UdmHTTPBufQuotedPrintableDecode(UDM_HTTPBUF * Buf,const char * src,size_t len)761 UdmHTTPBufQuotedPrintableDecode(UDM_HTTPBUF *Buf,
762 const char *src, size_t len)
763 {
764 UdmHTTPBufReset(Buf);
765 Buf->content= Buf->buf; /* No headers */
766 return UdmHTTPBufAppendQuotedPrintableDecode(Buf, src, len);
767 }
768
769
770 int
UdmHTTPBufAppendRecv(UDM_HTTPBUF * Buf,int fd,size_t len,int flags)771 UdmHTTPBufAppendRecv(UDM_HTTPBUF *Buf, int fd, size_t len, int flags)
772 {
773 int status;
774 if (UdmHTTPBufAvailableSize(Buf) < 2)
775 return 0;
776 if (UdmHTTPBufAvailableSize(Buf) < len + 1)
777 len= UdmHTTPBufAvailableSize(Buf) - 1;
778 if ((status= recv(fd, Buf->buf + Buf->size, len, flags)) > 0)
779 {
780 Buf->size+= status;
781 Buf->buf[Buf->size]= '\0';
782 }
783 return status;
784 }
785
786