1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "ats_fcgi_client.h"
20 #include "ats_fastcgi.h"
21 #include "fcgi_protocol.h"
22 #include "ts/ink_defs.h"
23 #include <iostream>
24 #include <sstream>
25 #include <string>
26 #include <locale>
27 #include <ts/ts.h>
28 #include <map>
29 #include <iterator>
30 #include "utils_internal.h"
31 #include <atscppapi/Headers.h>
32 #include <atscppapi/utils.h>
33
34 using namespace atscppapi;
35 using namespace ats_plugin;
36 using namespace std;
37
38 struct ats_plugin::FCGIClientState {
39 FCGI_BeginRequest *request;
40 FCGI_Header *header, *postHeader;
41 unsigned char *buff, *pBuffInc;
42 FCGIRecordList *records = nullptr;
43 TSHttpTxn txn_;
44 map<string, string> requestHeaders;
45 int request_id_;
46
FCGIClientStateats_plugin::FCGIClientState47 FCGIClientState()
48 : request(nullptr), header(nullptr), postHeader(nullptr), buff(nullptr), pBuffInc(nullptr), records(nullptr), request_id_(0){};
49
~FCGIClientStateats_plugin::FCGIClientState50 ~FCGIClientState()
51 {
52 request_id_ = 0;
53 free(request);
54 free(header);
55 TSfree(postHeader);
56 TSfree(buff);
57 TSfree(records);
58 };
59 };
60 // input to the constructor will be either unique transaction id or int type
61 // requestId
FCGIClientRequest(int request_id,TSHttpTxn txn)62 FCGIClientRequest::FCGIClientRequest(int request_id, TSHttpTxn txn)
63 {
64 first_chunk = true;
65 state_ = new FCGIClientState();
66 _headerRecord = nullptr;
67 state_->txn_ = txn;
68 state_->request_id_ = request_id;
69 state_->requestHeaders = GenerateFcgiRequestHeaders();
70 // TODO Call printFCGIRequestHeaders() to printFCGIHeaders
71 // printFCGIRequestHeaders();
72 string str("POST"), value;
73 if (str.compare(state_->requestHeaders["REQUEST_METHOD"]) == 0) {
74 Transaction &transaction = utils::internal::getTransaction(state_->txn_);
75 Headers &h = transaction.getClientRequest().getHeaders();
76
77 if (h.isInitialized()) {
78 string key("Content-Length");
79 atscppapi::header_field_iterator it = h.find(key);
80 if (it != h.end()) {
81 atscppapi::HeaderField hf(*it);
82 string value = hf.values(","); // delimiter for header values
83 state_->requestHeaders["CONTENT_LENGTH"] = value.c_str();
84 }
85
86 key = string("Content-type");
87 it = h.find(key);
88 if (it != h.end()) {
89 HeaderField hf1(*it);
90 string value = hf1.values(","); // delimiter for header values
91 state_->requestHeaders["CONTENT_TYPE"] = value.c_str();
92 }
93 }
94
95 int contentLength = 0;
96 string cl = state_->requestHeaders["CONTENT_LENGTH"];
97 stringstream strToInt(cl);
98 strToInt >> contentLength;
99 state_->buff = (unsigned char *)TSmalloc(BUF_SIZE + contentLength);
100 } else {
101 state_->buff = (unsigned char *)TSmalloc(BUF_SIZE);
102 }
103
104 state_->pBuffInc = state_->buff;
105 }
106
107 // destructor will reset the client_req_id and delete the recListState_ object
108 // holding response records received from fcgi server
~FCGIClientRequest()109 FCGIClientRequest::~FCGIClientRequest()
110 {
111 if (_headerRecord)
112 delete _headerRecord;
113
114 delete state_;
115 }
116
117 bool
endsWith(const std::string & mainStr,const std::string & toMatch)118 endsWith(const std::string &mainStr, const std::string &toMatch)
119 {
120 if (mainStr.size() >= toMatch.size() && mainStr.compare(mainStr.size() - toMatch.size(), toMatch.size(), toMatch) == 0)
121 return true;
122 else
123 return false;
124 }
125
126 map<string, string>
GenerateFcgiRequestHeaders()127 FCGIClientRequest::GenerateFcgiRequestHeaders()
128 {
129 map<string, string> fcgiReqHeader;
130 Transaction &transaction = utils::internal::getTransaction(state_->txn_);
131 Headers &h = transaction.getClientRequest().getHeaders();
132 if (h.isInitialized()) {
133 for (auto it : h) {
134 atscppapi::HeaderField hf(it);
135 std::string str = hf.name().c_str();
136 std::string http("HTTP_");
137 std::locale loc;
138
139 for (std::string::size_type i = 0; i < str.length(); ++i) {
140 http += std::toupper(str[i], loc);
141 }
142 fcgiReqHeader[http] = hf.values();
143 }
144 }
145
146 // if string ends with '/' char then request global html file to server
147 string index;
148 string requestScript = transaction.getClientRequest().getUrl().getPath();
149 if (endsWith(requestScript, "/")) {
150 ats_plugin::FcgiPluginConfig *gConfig = InterceptGlobal::plugin_data->getGlobalConfigObj();
151 index = gConfig->getHtml();
152 requestScript += index;
153 }
154
155 fcgiReqHeader["DOCUMENT_ROOT"] = InterceptGlobal::plugin_data->getGlobalConfigObj()->getDocumentRootDir();
156 fcgiReqHeader["SCRIPT_FILENAME"] = fcgiReqHeader["DOCUMENT_ROOT"] + requestScript;
157 fcgiReqHeader["GATEWAY_INTERFACE"] = "FastCGI/1.1";
158 fcgiReqHeader["REQUEST_METHOD"] = HTTP_METHOD_STRINGS[transaction.getClientRequest().getMethod()];
159 fcgiReqHeader["SCRIPT_NAME"] = "/" + requestScript;
160 fcgiReqHeader["QUERY_STRING"] = transaction.getClientRequest().getUrl().getQuery();
161 fcgiReqHeader["REQUEST_URI"] = "/" + requestScript;
162
163 // TODO map fcgiconfig with request headers.
164 // atsfcgiconfig::FCGIParams *params = fcgiGlobal::plugin_data->getGlobalConfigObj()->getFcgiParams();
165 // atsfcgiconfig::FCGIParams::iterator it = params->begin();
166 // for (it = params->begin(); it != params->end(); ++it)
167 // cout << it->first << " => " << it->second << endl;
168 fcgiReqHeader["SERVER_SOFTWARE"] = "ATS 7.1.1";
169 fcgiReqHeader["REMOTE_ADDR"] = "127.0.0.1";
170 fcgiReqHeader["REMOTE_PORT"] = "8090";
171 fcgiReqHeader["SERVER_ADDR"] = "127.0.0.1";
172 fcgiReqHeader["SERVER_PORT"] = "60000";
173 fcgiReqHeader["SERVER_NAME"] = "ATS 7.1.1";
174 fcgiReqHeader["SERVER_PROTOCOL"] = "HTTP/1.1";
175 fcgiReqHeader["FCGI_ROLE"] = "RESPONDER";
176 return fcgiReqHeader;
177 }
178
179 void
printFCGIRequestHeaders()180 FCGIClientRequest::printFCGIRequestHeaders()
181 {
182 for (const auto &it : state_->requestHeaders) {
183 cout << it.first << " => " << it.second << endl;
184 }
185 }
186
187 void
emptyParam()188 FCGIClientRequest::emptyParam()
189 {
190 string str("POST");
191 state_->pBuffInc = state_->buff;
192 // if Method is not post, then writing empty FCGI_STDIN to buffer
193 if (str.compare(state_->requestHeaders["REQUEST_METHOD"]) != 0) {
194 state_->postHeader = createHeader(FCGI_STDIN);
195 state_->postHeader->contentLengthB0 = 0;
196 state_->postHeader->contentLengthB1 = 0;
197 serialize(state_->pBuffInc, state_->postHeader, sizeof(FCGI_Header));
198 state_->pBuffInc += sizeof(FCGI_Header);
199 return;
200 }
201 TSDebug(PLUGIN_NAME, "empty Post Header Len: %ld ", state_->pBuffInc - state_->buff);
202 }
203
204 FCGI_Header *
createHeader(uchar type)205 FCGIClientRequest::createHeader(uchar type)
206 {
207 FCGI_Header *tmp = (FCGI_Header *)calloc(1, sizeof(FCGI_Header));
208 tmp->version = FCGI_VERSION_1;
209 tmp->type = type;
210 fcgiHeaderSetRequestId(tmp, state_->request_id_);
211 return tmp;
212 }
213
214 FCGI_BeginRequest *
createBeginRequest()215 FCGIClientRequest::createBeginRequest()
216 {
217 state_->request = (FCGI_BeginRequest *)TSmalloc(sizeof(FCGI_BeginRequest));
218 // TODO send the request id here
219 state_->request->header = createHeader(FCGI_BEGIN_REQUEST);
220 state_->request->body = (FCGI_BeginRequestBody *)calloc(1, sizeof(FCGI_BeginRequestBody));
221 state_->request->body->roleB0 = FCGI_RESPONDER;
222 state_->request->body->flags = FCGI_KEEP_CONN;
223 state_->request->header->contentLengthB0 = sizeof(FCGI_BeginRequestBody);
224
225 // serialize request header
226 serialize(state_->pBuffInc, state_->request->header, sizeof(FCGI_Header));
227 state_->pBuffInc += sizeof(FCGI_Header);
228 serialize(state_->pBuffInc, state_->request->body, sizeof(FCGI_BeginRequestBody));
229 state_->pBuffInc += sizeof(FCGI_BeginRequestBody);
230 TSDebug(PLUGIN_NAME, "Header Len: %ld ", state_->pBuffInc - state_->buff);
231 // FCGI Params headers
232 state_->header = createHeader(FCGI_PARAMS);
233 int len = 0, nb = 0;
234
235 for (const auto &it : state_->requestHeaders) {
236 nb = serializeNameValue(state_->pBuffInc, it);
237 len += nb;
238 }
239
240 state_->header->contentLengthB0 = BYTE_0(len);
241 state_->header->contentLengthB1 = BYTE_1(len);
242 TSDebug(PLUGIN_NAME, "ParamsLen: %d ContLenB0: %d ContLenB1: %d", len, state_->header->contentLengthB0,
243 state_->header->contentLengthB1);
244 serialize(state_->pBuffInc, state_->header, sizeof(FCGI_Header));
245 state_->pBuffInc += sizeof(FCGI_Header);
246
247 for (const auto &it : state_->requestHeaders) {
248 nb = serializeNameValue(state_->pBuffInc, it);
249 state_->pBuffInc += nb;
250 }
251
252 state_->header->contentLengthB0 = 0;
253 state_->header->contentLengthB1 = 0;
254 serialize(state_->pBuffInc, state_->header, sizeof(FCGI_Header));
255 state_->pBuffInc += sizeof(FCGI_Header);
256 return state_->request;
257 }
258
259 void
postBodyChunk()260 FCGIClientRequest::postBodyChunk()
261 {
262 state_->pBuffInc = state_->buff;
263 int dataLen = 0;
264 state_->postHeader = createHeader(FCGI_STDIN);
265 dataLen = postData.length();
266
267 state_->postHeader->contentLengthB0 = BYTE_0(dataLen);
268 state_->postHeader->contentLengthB1 = BYTE_1(dataLen);
269 serialize(state_->pBuffInc, state_->postHeader, sizeof(FCGI_Header));
270 state_->pBuffInc += sizeof(FCGI_Header);
271 memcpy(state_->pBuffInc, postData.c_str(), dataLen);
272 state_->pBuffInc += dataLen;
273
274 state_->postHeader->contentLengthB0 = 0;
275 state_->postHeader->contentLengthB1 = 0;
276 serialize(state_->pBuffInc, state_->postHeader, sizeof(FCGI_Header));
277 state_->pBuffInc += sizeof(FCGI_Header);
278 TSDebug(PLUGIN_NAME, "Serialized Post Data. Post Header Len: %ld ", state_->pBuffInc - state_->buff);
279 }
280
281 unsigned char *
addClientRequest(int & dataLen)282 FCGIClientRequest::addClientRequest(int &dataLen)
283 {
284 dataLen = state_->pBuffInc - state_->buff;
285 return state_->buff;
286 }
287
288 void
serialize(uchar * buffer,void * st,size_t size)289 FCGIClientRequest::serialize(uchar *buffer, void *st, size_t size)
290 {
291 memcpy(buffer, st, size);
292 }
293
294 uint32_t
serializeNameValue(uchar * buffer,const std::pair<string,string> & it)295 FCGIClientRequest::serializeNameValue(uchar *buffer, const std::pair<string, string> &it)
296 {
297 uchar *p = buffer;
298 uint32_t nl, vl;
299 nl = it.first.length();
300 vl = it.second.length();
301
302 if (nl < 128) {
303 *p++ = BYTE_0(nl);
304 } else {
305 *p++ = BYTE_3(nl);
306 *p++ = BYTE_2(nl);
307 *p++ = BYTE_1(nl);
308 *p++ = BYTE_0(nl);
309 }
310
311 if (vl < 128) {
312 *p++ = BYTE_0(vl);
313 } else {
314 *p++ = BYTE_3(vl);
315 *p++ = BYTE_2(vl);
316 *p++ = BYTE_1(vl);
317 *p++ = BYTE_0(vl);
318 }
319 memcpy(p, it.first.c_str(), nl);
320 p += nl;
321 memcpy(p, it.second.c_str(), vl);
322 p += vl;
323 return p - buffer;
324 }
325
326 void
fcgiHeaderSetRequestId(FCGI_Header * h,int request_id)327 FCGIClientRequest::fcgiHeaderSetRequestId(FCGI_Header *h, int request_id)
328 {
329 h->requestIdB0 = BYTE_0(request_id);
330 h->requestIdB1 = BYTE_1(request_id);
331 }
332
333 void
fcgiHeaderSetContentLen(FCGI_Header * h,uint16_t len)334 FCGIClientRequest::fcgiHeaderSetContentLen(FCGI_Header *h, uint16_t len)
335 {
336 h->contentLengthB0 = BYTE_0(len);
337 h->contentLengthB1 = BYTE_1(len);
338 }
339
340 uint32_t
fcgiHeaderGetContentLen(FCGI_Header * h)341 FCGIClientRequest::fcgiHeaderGetContentLen(FCGI_Header *h)
342 {
343 return (h->contentLengthB1 << 8) + h->contentLengthB0;
344 }
345
346 int
fcgiProcessHeader(uchar ch,FCGIRecordList * rec)347 FCGIClientRequest::fcgiProcessHeader(uchar ch, FCGIRecordList *rec)
348 {
349 FCGI_Header *h;
350 FCGI_State *state = &(rec->state);
351 h = rec->header;
352
353 switch (*state) {
354 case fcgi_state_version:
355 h->version = ch;
356 *state = fcgi_state_type;
357 break;
358 case fcgi_state_type:
359 h->type = ch;
360 *state = fcgi_state_request_id_hi;
361 break;
362 case fcgi_state_request_id_hi:
363 h->requestIdB1 = ch;
364 *state = fcgi_state_request_id_lo;
365 break;
366 case fcgi_state_request_id_lo:
367 h->requestIdB0 = ch;
368 *state = fcgi_state_content_len_hi;
369 break;
370 case fcgi_state_content_len_hi:
371 h->contentLengthB1 = ch;
372 *state = fcgi_state_content_len_lo;
373 break;
374 case fcgi_state_content_len_lo:
375 h->contentLengthB0 = ch;
376 *state = fcgi_state_padding_len;
377 break;
378 case fcgi_state_padding_len:
379 h->paddingLength = ch;
380 *state = fcgi_state_reserved;
381 break;
382 case fcgi_state_reserved:
383 h->reserved = ch;
384 *state = fcgi_state_content_begin;
385 break;
386
387 case fcgi_state_content_begin:
388 case fcgi_state_content_proc:
389 case fcgi_state_padding:
390 case fcgi_state_done:
391 return FCGI_PROCESS_DONE;
392 }
393 return FCGI_PROCESS_AGAIN;
394 }
395
396 int
fcgiProcessContent(uchar ** beg_buf,uchar * end_buf,FCGIRecordList * rec)397 FCGIClientRequest::fcgiProcessContent(uchar **beg_buf, uchar *end_buf, FCGIRecordList *rec)
398 {
399 size_t tot_len, con_len, cpy_len, offset, nb = end_buf - *beg_buf;
400 FCGI_State *state = &(rec->state);
401 FCGI_Header *h = rec->header;
402 offset = rec->offset;
403
404 if (*state == fcgi_state_padding) {
405 *state = fcgi_state_done;
406 *beg_buf += (size_t)((int)rec->length - (int)offset + (int)h->paddingLength);
407 return FCGI_PROCESS_DONE;
408 }
409
410 con_len = rec->length - offset;
411 tot_len = con_len + h->paddingLength;
412
413 if (con_len <= nb)
414 cpy_len = con_len;
415 else {
416 cpy_len = nb;
417 }
418
419 memcpy(rec->content + offset, *beg_buf, cpy_len);
420
421 if (tot_len <= nb) {
422 rec->offset += tot_len;
423 *state = fcgi_state_done;
424 *beg_buf += tot_len;
425 return FCGI_PROCESS_DONE;
426 } else if (con_len <= nb) {
427 /* Have to still skip all or some of padding */
428 *state = fcgi_state_padding;
429 rec->offset += nb;
430 *beg_buf += nb;
431 return FCGI_PROCESS_AGAIN;
432 } else {
433 rec->offset += nb;
434 *beg_buf += nb;
435 return FCGI_PROCESS_AGAIN;
436 }
437
438 return 0;
439 }
440
441 int
fcgiProcessRecord(uchar ** beg_buf,uchar * end_buf,FCGIRecordList * rec)442 FCGIClientRequest::fcgiProcessRecord(uchar **beg_buf, uchar *end_buf, FCGIRecordList *rec)
443 {
444 int rv;
445 while (rec->state < fcgi_state_content_begin) {
446 if ((rv = fcgiProcessHeader(**beg_buf, rec)) == FCGI_PROCESS_ERR)
447 return FCGI_PROCESS_ERR;
448 (*beg_buf)++;
449 if (*beg_buf == end_buf)
450 return FCGI_PROCESS_AGAIN;
451 }
452 if (rec->state == fcgi_state_content_begin) {
453 rec->length = fcgiHeaderGetContentLen(rec->header);
454 rec->content = (uchar *)TSmalloc(rec->length);
455 rec->state = (FCGI_State)(int(rec->state) + 1);
456 }
457
458 return fcgiProcessContent(beg_buf, end_buf, rec);
459 }
460
461 static char *
convert_mime_hdr_to_string(TSMBuffer bufp,TSMLoc hdr_loc)462 convert_mime_hdr_to_string(TSMBuffer bufp, TSMLoc hdr_loc)
463 {
464 TSIOBuffer output_buffer;
465 TSIOBufferReader reader;
466 int64_t total_avail;
467
468 TSIOBufferBlock block;
469 const char *block_start;
470 int64_t block_avail;
471
472 char *output_string;
473 int output_len;
474
475 output_buffer = TSIOBufferCreate();
476
477 if (!output_buffer) {
478 TSError("[InkAPITest] couldn't allocate IOBuffer");
479 }
480
481 reader = TSIOBufferReaderAlloc(output_buffer);
482
483 /* This will print just MIMEFields and not
484 the http request line */
485 TSMimeHdrPrint(bufp, hdr_loc, output_buffer);
486
487 /* Find out how the big the complete header is by
488 seeing the total bytes in the buffer. We need to
489 look at the buffer rather than the first block to
490 see the size of the entire header */
491 total_avail = TSIOBufferReaderAvail(reader);
492
493 /* Allocate the string with an extra byte for the string
494 terminator */
495 output_string = (char *)TSmalloc(total_avail + 1);
496 output_len = 0;
497
498 /* We need to loop over all the buffer blocks to make
499 sure we get the complete header since the header can
500 be in multiple blocks */
501 block = TSIOBufferReaderStart(reader);
502 while (block) {
503 block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
504
505 /* We'll get a block pointer back even if there is no data
506 left to read so check for this condition and break out of
507 the loop. A block with no data to read means we've exhausted
508 buffer of data since if there was more data on a later
509 block in the chain, this block would have been skipped over */
510 if (block_avail == 0) {
511 break;
512 }
513
514 memcpy(output_string + output_len, block_start, block_avail);
515 output_len += block_avail;
516
517 /* Consume the data so that we get to the next block */
518 TSIOBufferReaderConsume(reader, block_avail);
519
520 /* Get the next block now that we've consumed the
521 data off the last block */
522 block = TSIOBufferReaderStart(reader);
523 }
524
525 /* Terminate the string */
526 output_string[output_len] = '\0';
527 output_len++;
528
529 /* Free up the TSIOBuffer that we used to print out the header */
530 TSIOBufferReaderFree(reader);
531 TSIOBufferDestroy(output_buffer);
532
533 return output_string;
534 }
535
536 bool
fcgiProcessBuffer(uchar * beg_buf,uchar * end_buf,std::ostringstream & output)537 FCGIClientRequest::fcgiProcessBuffer(uchar *beg_buf, uchar *end_buf, std::ostringstream &output)
538 {
539 if (!_headerRecord)
540 _headerRecord = new FCGIRecordList;
541
542 while (1) {
543 if (_headerRecord->state == fcgi_state_done) {
544 FCGIRecordList *tmp = _headerRecord;
545 _headerRecord = new FCGIRecordList();
546 delete tmp;
547 }
548
549 if (fcgiProcessRecord(&beg_buf, end_buf, _headerRecord) == FCGI_PROCESS_DONE) {
550 if (first_chunk) {
551 string start = std::string((char *)_headerRecord->content, _headerRecord->length);
552 string end("\r\n\r\n");
553 string headerString;
554 int foundPos = start.find(end);
555 if (foundPos != -1) {
556 headerString = start.substr(0, foundPos + 4);
557 }
558 const char *buff = headerString.c_str();
559 const char *start1;
560 const char *endPtr;
561 start1 = buff;
562 endPtr = buff + strlen(buff) + 1;
563 char *temp;
564 TSMLoc mime_hdr_loc1 = (TSMLoc) nullptr;
565 TSParseResult retval;
566 TSMimeParser parser = TSMimeParserCreate();
567 TSMBuffer bufp = TSMBufferCreate();
568 TSMimeHdrCreate(bufp, &mime_hdr_loc1);
569 if ((retval = TSMimeHdrParse(parser, bufp, mime_hdr_loc1, &start1, endPtr)) == TS_PARSE_ERROR) {
570 TSDebug(PLUGIN_NAME, "[FCGIClientRequest:%s] Hdr Parse Error.", __FUNCTION__);
571 } else {
572 if (retval == TS_PARSE_DONE) {
573 temp = convert_mime_hdr_to_string(bufp, mime_hdr_loc1); // Implements TSMimeHdrPrint.
574 if (strcmp(buff, temp) == 0) {
575 Headers h(bufp, mime_hdr_loc1);
576 string key("Status");
577 if (h.isInitialized()) {
578 atscppapi::header_field_iterator it = h.find(key);
579 if (it != h.end()) {
580 atscppapi::HeaderField hf(*it);
581 string value = hf.values(","); // delimiter for header values
582 output << HTTP_VERSION_STRINGS[HTTP_VERSION_1_1] << " ";
583 output << value.c_str() << "\r\n";
584 } else {
585 output << "HTTP/1.0 200 OK\r\n";
586 }
587 // it = h.begin();
588 // for (it = h.begin(); it != h.end(); ++it) {
589 // atscppapi::HeaderField hf(*it);
590 // std::cout << "Name => " << hf.name() << "Value => " << hf.values() << std::endl;
591 // }
592 }
593 } else {
594 TSDebug(PLUGIN_NAME, "[FCGIClientRequest:%s] Incorrect Parsing.", __FUNCTION__);
595 output << "HTTP/1.0 200 OK\r\n";
596 }
597 TSfree(temp);
598 }
599 }
600
601 TSMimeHdrDestroy(bufp, mime_hdr_loc1);
602 TSHandleMLocRelease(bufp, TS_NULL_MLOC, mime_hdr_loc1);
603 TSMBufferDestroy(bufp);
604 TSMimeParserDestroy(parser);
605 // OS(XXX): merge -- check later, currently leaning towards that we do not have
606 // to do this.
607 // TSfree(buff);
608 first_chunk = false;
609 }
610 if (_headerRecord->header->type == FCGI_STDOUT) {
611 output << std::string((const char *)_headerRecord->content, _headerRecord->length);
612 }
613 if (_headerRecord->header->type == FCGI_STDERR) {
614 // XXX(oschaaf): we may want to treat this differently, but for now this will do.
615 output << "HTTP/1.0 500 Server Error\r\n\r\n";
616 output << std::string((const char *)_headerRecord->content, _headerRecord->length);
617 TSDebug(PLUGIN_NAME, "[ FCGIClientRequest:%s ] Response FCGI_STDERR.*****\n\n", __FUNCTION__);
618 return true;
619 }
620 if (_headerRecord->header->type == FCGI_END_REQUEST) {
621 TSDebug(PLUGIN_NAME, "[ FCGIClientRequest:%s ] Response FCGI_END_REQUEST.*****\n\n", __FUNCTION__);
622 return true;
623 }
624 }
625
626 if (beg_buf == end_buf)
627 return false;
628 }
629 }
630
631 bool
fcgiDecodeRecordChunk(uchar * beg_buf,size_t remain,std::ostringstream & output)632 FCGIClientRequest::fcgiDecodeRecordChunk(uchar *beg_buf, size_t remain, std::ostringstream &output)
633 {
634 return fcgiProcessBuffer((uchar *)beg_buf, (uchar *)beg_buf + (size_t)remain, output);
635 }
636
637 void
print_bytes(uchar * buf,int n)638 FCGIClientRequest::print_bytes(uchar *buf, int n)
639 {
640 int i;
641 printf("{");
642 for (i = 0; i < n; i++)
643 printf("%02x", buf[i]);
644 printf("}\n");
645 }
646