542bae02f0b4fe796e9f4753d3675a99b067ea49
[kamailio] / src / modules / lost / utilities.c
1 /*
2  * lost module utility functions
3  *
4  * Copyright (C) 2019 Wolfgang Kampichler
5  * DEC112, FREQUENTIS AG
6  *
7  * This file is part of Kamailio, a free SIP server.
8  *
9  * Kamailio is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * Kamailio is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 /*!
26  * \file
27  * \brief Kamailio lost :: utilities
28  * \ingroup lost
29  * Module: \ref lost
30  */
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <time.h>
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/parser.h>
40 #include "../../core/parser/msg_parser.h"
41 #include "../../core/parser/parse_content.h"
42 #include "../../core/parser/parse_uri.h"
43 #include "../../core/parser/parse_from.h"
44 #include "../../core/parser/parse_ppi_pai.h"
45 #include "../../core/dprint.h"
46 #include "../../core/mem/mem.h"
47 #include "../../core/mem/shm_mem.h"
48 #include "../../core/rand/kam_rand.h"
49
50 #include "pidf.h"
51 #include "utilities.h"
52
53 /*
54  * lost_trim_content(dest, lgth)
55  * removes whitespace that my occur in a content of an xml element
56  */
57 char *lost_trim_content(char *str, int *lgth)
58 {
59         char *end;
60
61         while(isspace(*str))
62                 str++;
63
64         if(*str == 0)
65                 return NULL;
66
67         end = str + strlen(str) - 1;
68
69         while(end > str && isspace(*end))
70                 end--;
71
72         *(end + 1) = '\0';
73
74         *lgth = (end + 1) - str;
75
76         return str;
77 }
78
79 /*
80  * lost_rand_str(dest, length)
81  * creates a random string used as temporary id in a findService request
82  */
83 void lost_rand_str(char *dest, size_t lgth)
84 {
85         size_t index;
86         char charset[] = "0123456789"
87                                          "abcdefghijklmnopqrstuvwxyz"
88                                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
89         while(lgth-- > 0) {
90                 index = (double)kam_rand() / RAND_MAX * (sizeof charset - 1);
91                 *dest++ = charset[index];
92         }
93         *dest = '\0';
94 }
95
96 /*
97  * lost_free_loc(ptr)
98  * frees a location object
99  */
100 void lost_free_loc(p_loc_t ptr)
101 {
102         pkg_free(ptr->identity);
103         pkg_free(ptr->urn);
104         pkg_free(ptr->longitude);
105         pkg_free(ptr->latitude);
106         pkg_free(ptr);
107 }
108
109 /*
110  * lost_free_string(ptr)
111  * frees and resets a string
112  */
113 void lost_free_string(str *string)
114 {
115         str ptr = *string;
116
117         if(ptr.s) {
118                 pkg_free(ptr.s);
119                 ptr.s = NULL;
120                 ptr.len = 0;
121         }
122 }
123
124 /*
125  * lost_new_loc(urn)
126  * creates a new location object in private memory and returns a pointer
127  */
128 p_loc_t lost_new_loc(str rurn)
129 {
130         s_loc_t *ptr = NULL;;
131         char *id = NULL;
132         char *urn = NULL;
133
134         ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));
135         if(ptr == NULL) {
136                 goto err;
137         }
138
139         id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);
140         if(id == NULL) {
141                 pkg_free(ptr);
142                 goto err;
143         }
144
145         urn = (char *)pkg_malloc(rurn.len + 1);
146         if(urn == NULL) {
147                 pkg_free(ptr);
148                 pkg_free(id);
149                 goto err;
150         }
151
152         memset(urn, 0, rurn.len + 1);
153         memcpy(urn, rurn.s, rurn.len);
154         urn[rurn.len] = '\0';
155
156         lost_rand_str(id, RANDSTRSIZE);
157
158         ptr->identity = id;
159         ptr->urn = urn;
160         ptr->longitude = NULL;
161         ptr->latitude = NULL;
162         ptr->radius = 0;
163         ptr->recursive = 0;
164
165         return ptr;
166
167 err:    
168         LM_ERR("no more private memory\n");
169         return NULL;
170 }
171
172 /*
173  * lost_get_content(node, name, lgth)
174  * gets a nodes "name" content and returns string allocated in private memory
175  */
176 char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)
177 {
178         xmlNodePtr cur = node;
179         char *content;
180         char *cnt = NULL;
181         int len;
182
183         *lgth = 0;
184         content = xmlNodeGetNodeContentByName(cur, name, NULL);
185         if (content == NULL) {
186                 LM_ERR("could not get XML node content\n");
187                 return cnt;
188         } else {
189                 len = strlen(content);
190                 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
191                 if(cnt == NULL) {
192                         LM_ERR("no more private memory\n");
193                         xmlFree(content);
194                         return cnt;
195                 }
196                 memset(cnt, 0, len + 1);
197                 memcpy(cnt, content, len);
198                 cnt[len] = '\0';
199         }
200
201         xmlFree(content);
202         *lgth = strlen(cnt);
203
204         return cnt;
205 }
206
207 /*
208  * lost_get_property(node, name, lgth)
209  * gets a nodes property "name" and returns string allocated in private memory
210  */
211 char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)
212 {
213         xmlNodePtr cur = node;
214         char *content;
215         char *cnt = NULL;
216         int len;
217
218         *lgth = 0;
219         content = xmlNodeGetAttrContentByName(cur, name);
220         if (content == NULL) {
221                 LM_ERR("could not get XML node content\n");
222                 return cnt;
223         } else {
224                 len = strlen(content);
225                 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
226                 if(cnt == NULL) {
227                         LM_ERR("no more private memory\n");
228                         xmlFree(content);
229                         return cnt;
230                 }
231                 memset(cnt, 0, len + 1);
232                 memcpy(cnt, content, len);
233                 cnt[len] = '\0';
234         }
235
236         xmlFree(content);
237         *lgth = strlen(cnt);
238
239         return cnt;
240 }
241
242 /*
243  * lost_get_childname(name, lgth)
244  * gets a nodes child name and returns string allocated in private memory
245  */
246 char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)
247 {
248         xmlNodePtr cur = node;
249         xmlNodePtr parent = NULL;
250         xmlNodePtr child = NULL;
251         char *cnt = NULL;
252         int len;
253
254         *lgth = 0;
255         parent = xmlNodeGetNodeByName(cur, name, NULL);
256         child = parent->children;
257
258         if(child) {
259                 len = strlen((char *)child->name);
260                 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
261                 if(cnt == NULL) {
262                         LM_ERR("no more private memory\n");
263                         return cnt;
264                 }
265
266                 memset(cnt, 0, len + 1);
267                 memcpy(cnt, child->name, len);
268                 cnt[len] = '\0';
269
270                 *lgth = strlen(cnt);
271         }
272         return cnt;
273 }
274
275 /*
276  * lost_get_geolocation_header(msg, lgth)
277  * gets the Geolocation header value and returns string allocated in
278  * private memory
279  */
280 char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)
281 {
282         struct hdr_field *hf;
283         char *res = NULL;
284
285         *lgth = 0;
286
287         if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
288                 LM_ERR("failed to parse geolocation header\n");
289                 return res;
290         }
291
292         for(hf = msg->headers; hf; hf = hf->next) {
293                 if((hf->type == HDR_OTHER_T)
294                                 && (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {
295                         /* possible hit */
296                         if(strncasecmp(
297                                            hf->name.s, LOST_GEOLOC_HEADER, LOST_GEOLOC_HEADER_SIZE)
298                                         == 0) {
299
300                                 res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));
301                                 if(res == NULL) {
302                                         LM_ERR("no more private memory\n");
303                                         return res;
304                                 } else {
305                                         memset(res, 0, hf->body.len + 1);
306                                         memcpy(res, hf->body.s, hf->body.len + 1);
307                                         res[hf->body.len] = '\0';
308
309                                         *lgth = strlen(res);
310                                 }
311                         } else {
312                                 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
313                                                 hf->body.len);
314                         }
315                         break;
316                 }
317         }
318         return res;
319 }
320
321 /*
322  * lost_get_pai_header(msg, lgth)
323  * gets the P-A-I header value and returns string allocated in
324  * private memory
325  */
326 char *lost_get_pai_header(struct sip_msg *msg, int *lgth)
327 {
328         struct hdr_field *hf;
329         to_body_t *pai_body;
330         char *res = NULL;
331
332         *lgth = 0;
333
334         if (parse_headers(msg, HDR_PAI_F, 0) == -1) {
335                 LM_ERR("could not parse P-A-I header\n");
336                 return res;
337         }
338
339         for(hf = msg->headers; hf; hf = hf->next) {
340                 if((hf->type == HDR_PAI_T)
341                                 && (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {
342                         /* possible hit */
343                         if(strncasecmp(hf->name.s, LOST_PAI_HEADER, LOST_PAI_HEADER_SIZE)
344                                         == 0) {
345
346                                 LM_DBG("P-A-I body:  [%.*s]\n", hf->body.len, hf->body.s);
347
348                                 /* first, get some memory */
349                                 pai_body = pkg_malloc(sizeof(to_body_t));
350                                 if (pai_body == NULL) {
351                                         LM_ERR("no more private memory\n");
352                                         return res;
353                                 }
354                                 /* parse P-A-I body */
355                                 memset(pai_body, 0, sizeof(to_body_t));
356                                 parse_to(hf->body.s, hf->body.s + hf->body.len + 1, pai_body);
357                                 if (pai_body->error == PARSE_ERROR) {
358                                         LM_ERR("bad P-A-I header\n");
359                                         pkg_free(pai_body);
360                                         return res;
361                                 }
362                                 if (pai_body->error == PARSE_OK) {
363                                         res = (char *)pkg_malloc((pai_body->uri.len + 1) * sizeof(char));
364                                         if(res == NULL) {
365                                                 LM_ERR("no more private memory\n");
366                                                 pkg_free(pai_body);
367                                                 return res;
368                                         } else {
369                                                 memset(res, 0, pai_body->uri.len + 1);
370                                                 memcpy(res, pai_body->uri.s, pai_body->uri.len + 1);
371                                                 res[pai_body->uri.len] = '\0';
372                                                 pkg_free(pai_body);
373
374                                                 *lgth = strlen(res);
375                                         }
376                                 }
377                         } else {
378                                 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
379                                                 hf->body.len);
380                         }
381                         break;
382                 }
383         }
384         return res;
385 }
386
387 /*
388  * lost_get_from_header(msg, lgth)
389  * gets the From header value and returns string allocated in
390  * private memory
391  */
392 char *lost_get_from_header(struct sip_msg *msg, int *lgth)
393 {
394         to_body_t *f_body;
395         char *res = NULL;
396
397         *lgth = 0;
398
399         if(parse_headers(msg, HDR_FROM_F, 0) == -1) {
400                 LM_ERR("failed to parse From header\n");
401                 return res;
402         }
403
404         if(msg->from == NULL || get_from(msg) == NULL) {
405                 LM_ERR("From header not found\n");
406                 return res;
407         }
408         f_body = get_from(msg);
409
410         LM_DBG("From body:  [%.*s]\n", f_body->body.len, f_body->body.s);
411
412         res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));
413         if(res == NULL) {
414                 LM_ERR("no more private memory\n");
415                 return res;
416         } else {
417                 memset(res, 0, f_body->uri.len + 1);
418                 memcpy(res, f_body->uri.s, f_body->uri.len + 1);
419                 res[f_body->uri.len] = '\0';
420
421                 *lgth = strlen(res);
422         }
423         return res;
424 }
425
426 /*
427  * lost_parse_location_info(node, loc)
428  * parses locationResponse and writes results to location object
429  */
430 int lost_parse_location_info(xmlNodePtr node, p_loc_t loc)
431 {
432         char bufLat[BUFSIZE];
433         char bufLon[BUFSIZE];
434         int iRadius;
435         char *content = NULL;
436         int ret = -1;
437
438         xmlNodePtr cur = node;
439
440         content = xmlNodeGetNodeContentByName(cur, "pos", NULL);
441         if(content) {
442                 sscanf(content, "%s %s", bufLat, bufLon);
443
444                 loc->latitude = (char *)pkg_malloc(strlen((char *)bufLat) + 1);
445                 snprintf(loc->latitude, strlen((char *)bufLat) + 1, "%s",
446                                 (char *)bufLat);
447
448                 loc->longitude = (char *)pkg_malloc(strlen((char *)bufLon) + 1);
449                 snprintf(loc->longitude, strlen((char *)bufLon) + 1, "%s",
450                                 (char *)bufLon);
451
452                 loc->radius = 0;
453                 ret = 0;
454         }
455
456         content = xmlNodeGetNodeContentByName(cur, "radius", NULL);
457         if(content) {
458                 iRadius = 0;
459
460                 sscanf(content, "%d", &iRadius);
461                 loc->radius = iRadius;
462                 ret = 0;
463         }
464
465         if(ret < 0) {
466                 LM_ERR("could not parse location information\n");
467         }
468         return ret;
469 }
470
471 /*
472  * lost_held_location_request(id, lgth)
473  * assembles and returns locationRequest string (allocated in private memory)
474  */
475 char *lost_held_location_request(char *id, int *lgth)
476 {
477         int buffersize = 0;
478
479         char buf[BUFSIZE];
480         char *doc = NULL;
481
482         xmlChar *xmlbuff = NULL;
483         xmlDocPtr request = NULL;
484
485         xmlNodePtr ptrLocationRequest = NULL;
486         xmlNodePtr ptrLocationType = NULL;
487         xmlNodePtr ptrDevice = NULL;
488
489         xmlKeepBlanksDefault(1);
490         *lgth = 0;
491
492         /*
493 https://tools.ietf.org/html/rfc6155
494
495 <?xml version="1.0" encoding="UTF-8"?>
496 <locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">
497     <locationType exact="true">geodetic locationURI</locationType>
498     <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
499         <uri>sip:user@example.net</uri>
500     </device>
501 </locationRequest>
502 */
503
504         /* create request */
505         request = xmlNewDoc(BAD_CAST "1.0");
506         if(!request) {
507                 LM_ERR("locationRequest xmlNewDoc() failed\n");
508                 return doc;
509         }
510         /* locationRequest - element */
511         ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");
512         if(!ptrLocationRequest) {
513                 LM_ERR("locationRequest xmlNewNode() failed\n");
514                 xmlFreeDoc(request);
515                 return doc;
516         }
517         xmlDocSetRootElement(request, ptrLocationRequest);
518         /* properties */
519         xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",
520                         BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");
521         xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST "8");
522         /* locationType - element */
523         ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,
524                         BAD_CAST "locationType", BAD_CAST "geodetic locationURI");
525         /* properties */
526         xmlNewProp(ptrLocationType, BAD_CAST "exact", BAD_CAST "false");
527         /* device - element */
528         ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);
529         if(!ptrDevice) {
530                 LM_ERR("locationRequest xmlNewChild() failed\n");
531                 xmlFreeDoc(request);
532                 return doc;
533         }
534         /* properties */
535         xmlNewProp(ptrDevice, BAD_CAST "xmlns",
536                         BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");
537         /* uri - element */
538         snprintf(buf, BUFSIZE, "%s", id);
539         xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST buf);
540
541         xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
542         if(!xmlbuff) {
543                 LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");
544                 xmlFreeDoc(request);
545                 return doc;
546         }
547
548         doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
549         if(doc == NULL) {
550                 LM_ERR("no more private memory\n");
551                 xmlFree(xmlbuff);
552                 xmlFreeDoc(request);
553                 return doc;
554         }
555
556         memset(doc, 0, buffersize + 1);
557         memcpy(doc, (char *)xmlbuff, buffersize);
558         doc[buffersize] = '\0';
559
560         *lgth = strlen(doc);
561
562         xmlFree(xmlbuff);
563         xmlFreeDoc(request);
564
565         return doc;
566 }
567
568 /*
569  * lost_find_service_request(loc, lgth)
570  * assembles and returns findService request string (allocated in private memory)
571  */
572 char *lost_find_service_request(p_loc_t loc, int *lgth)
573 {
574         int buffersize = 0;
575
576         char buf[BUFSIZE];
577         char *doc = NULL;
578
579         xmlChar *xmlbuff = NULL;
580         xmlDocPtr request = NULL;
581
582         xmlNodePtr ptrFindService = NULL;
583         xmlNodePtr ptrLocation = NULL;
584         xmlNodePtr ptrPoint = NULL;
585         xmlNodePtr ptrCircle = NULL;
586         xmlNodePtr ptrRadius = NULL;
587
588         xmlKeepBlanksDefault(1);
589         *lgth = 0;
590
591         /*
592 https://tools.ietf.org/html/rfc5222
593
594 <?xml version="1.0" encoding="UTF-8"?>
595 <findService
596  xmlns="urn:ietf:params:xml:ns:lost1"
597  xmlns:p2="http://www.opengis.net/gml"
598  serviceBoundary="value"
599  recursive="true">
600     <location id="6020688f1ce1896d" profile="geodetic-2d">
601         <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">
602             <p2:pos>37.775 -122.422</p2:pos>
603         </p2:Point>
604     </location>
605     <service>urn:service:sos.police</service>
606 </findService>
607  */
608         /* create request */
609         request = xmlNewDoc(BAD_CAST "1.0");
610         if(!request) {
611                 LM_ERR("findService request xmlNewDoc() failed\n");
612                 return doc;
613         }
614         /* findService - element */
615         ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");
616         if(!ptrFindService) {
617                 LM_ERR("findService xmlNewNode() failed\n");
618                 xmlFreeDoc(request);
619                 return doc;
620         }
621         xmlDocSetRootElement(request, ptrFindService);
622         /* set properties */
623         xmlNewProp(ptrFindService, BAD_CAST "xmlns",
624                         BAD_CAST "urn:ietf:params:xml:ns:lost1");
625         xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",
626                         BAD_CAST "http://www.opengis.net/gml");
627         xmlNewProp(
628                         ptrFindService, BAD_CAST "serviceBoundary", BAD_CAST "reference");
629         xmlNewProp(ptrFindService, BAD_CAST "recursive", BAD_CAST "true");
630         /* location - element */
631         ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);
632         xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);
633         xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST "geodetic-2d");
634         /* set pos */
635         snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);
636         /* Point */
637         if(loc->radius == 0) {
638                 ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);
639                 if(!ptrPoint) {
640                         LM_ERR("locationRequest xmlNewChild() failed\n");
641                         xmlFreeDoc(request);
642                         return doc;
643                 }
644                 xmlNewProp(ptrPoint, BAD_CAST "xmlns",
645                                 BAD_CAST "http://www.opengis.net/gml");
646                 xmlNewProp(ptrPoint, BAD_CAST "srsName",
647                                 BAD_CAST "urn:ogc:def:crs:EPSG::4326");
648                 /* pos */
649                 xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);
650         } else {
651                 /* circle - Point */
652                 ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);
653                 if(!ptrCircle) {
654                         LM_ERR("locationRequest xmlNewChild() failed\n");
655                         xmlFreeDoc(request);
656                         return doc;
657                 }
658                 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",
659                                 BAD_CAST "http://www.opengis.net/gml");
660                 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",
661                                 BAD_CAST "http://www.opengis.net/pidflo/1.0");
662                 xmlNewProp(ptrCircle, BAD_CAST "srsName",
663                                 BAD_CAST "urn:ogc:def:crs:EPSG::4326");
664                 /* pos */
665                 xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);
666                 /* circle - radius */
667                 snprintf(buf, BUFSIZE, "%d", loc->radius);
668                 ptrRadius = xmlNewChild(
669                                 ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);
670                 if(!ptrRadius) {
671                         LM_ERR("locationRequest xmlNewChild() failed\n");
672                         xmlFreeDoc(request);
673                         return doc;
674                 }
675                 xmlNewProp(ptrRadius, BAD_CAST "uom",
676                                 BAD_CAST "urn:ogc:def:uom:EPSG::9001");
677         }
678         /* service - element */
679         snprintf(buf, BUFSIZE, "%s", loc->urn);
680         xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);
681
682         xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
683         if(!xmlbuff) {
684                 LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");
685                 xmlFreeDoc(request);
686                 return doc;
687         }
688
689         doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
690         if(doc == NULL) {
691                 LM_ERR("no more private memory\n");
692                 xmlFree(xmlbuff);
693                 xmlFreeDoc(request);
694                 return doc;
695         }
696
697         memset(doc, 0, buffersize + 1);
698         memcpy(doc, (char *)xmlbuff, buffersize);
699         doc[buffersize] = '\0';
700
701         *lgth = strlen(doc);
702
703         xmlFree(xmlbuff);
704         xmlFreeDoc(request);
705
706         return doc;
707 }