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",&lt) ; token;
166        token= udm_strtok_r(NULL,"\r\n",&lt))
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",&lt)))
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",&lt) ; token;
254        token = udm_strtok_r(NULL,"\r\n",&lt))
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