1 /** @file
2 
3   Implements unit test for SDK APIs
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 // Turn off -Wdeprecated so that we can still test our own deprecated APIs.
25 #if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
26 #pragma GCC diagnostic ignored "-Wdeprecated"
27 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
28 #endif
29 
30 #include <sys/types.h>
31 #include <arpa/inet.h> /* For htonl */
32 
33 #include <cerrno>
34 #include <pthread.h>
35 #include <unistd.h>
36 #include <cstdio>
37 #include <cstring>
38 
39 #include "tscore/ink_config.h"
40 #include "tscore/ink_sprintf.h"
41 #include "tscore/ink_file.h"
42 #include "tscore/Regression.h"
43 #include "tscore/Filenames.h"
44 #include "ts/ts.h"
45 #include "ts/experimental.h"
46 #include "records/I_RecCore.h"
47 
48 #include "P_Net.h"
49 #include "records/I_RecHttp.h"
50 
51 #include "http/HttpSM.h"
52 #include "tscore/TestBox.h"
53 
54 // This used to be in InkAPITestTool.cc, which we'd just #include here... But that seemed silly.
55 #define SDBG_TAG "SockServer"
56 #define CDBG_TAG "SockClient"
57 
58 #define IP(a, b, c, d) htonl((a) << 24 | (b) << 16 | (c) << 8 | (d))
59 
60 #define SET_TEST_HANDLER(_d, _s) \
61   {                              \
62     _d = _s;                     \
63   }
64 
65 #define MAGIC_ALIVE 0xfeedbaba
66 #define MAGIC_DEAD 0xdeadbeef
67 
68 #define SYNSERVER_LISTEN_PORT 3300
69 #define SYNSERVER_DUMMY_PORT -1
70 
71 #define PROXY_CONFIG_NAME_HTTP_PORT "proxy.config.http.server_port"
72 #define PROXY_HTTP_DEFAULT_PORT 8080
73 
74 #define REQUEST_MAX_SIZE 4095
75 #define RESPONSE_MAX_SIZE 4095
76 
77 #define HTTP_REQUEST_END "\r\n\r\n"
78 
79 // each request/response includes an identifier as a Mime field
80 #define X_REQUEST_ID "X-Request-ID"
81 #define X_RESPONSE_ID "X-Response-ID"
82 
83 #define ERROR_BODY "TESTING ERROR PAGE"
84 #define TRANSFORM_APPEND_STRING "This is a transformed response"
85 
86 //////////////////////////////////////////////////////////////////////////////
87 // STRUCTURES
88 //////////////////////////////////////////////////////////////////////////////
89 
90 using TxnHandler = int (*)(TSCont, TSEvent, void *);
91 
92 /* Server transaction structure */
93 struct ServerTxn {
94   TSVConn vconn;
95 
96   TSVIO read_vio;
97   TSIOBuffer req_buffer;
98   TSIOBufferReader req_reader;
99 
100   TSVIO write_vio;
101   TSIOBuffer resp_buffer;
102   TSIOBufferReader resp_reader;
103 
104   char request[REQUEST_MAX_SIZE + 1];
105   int request_len;
106 
107   TxnHandler current_handler;
108   unsigned int magic;
109 };
110 
111 /* Server structure */
112 struct SocketServer {
113   int accept_port;
114   TSAction accept_action;
115   TSCont accept_cont;
116   unsigned int magic;
117 };
118 
119 enum RequestStatus {
120   REQUEST_SUCCESS,
121   REQUEST_INPROGRESS,
122   REQUEST_FAILURE,
123 };
124 
125 /* Client structure */
126 struct ClientTxn {
127   TSVConn vconn;
128 
129   TSVIO read_vio;
130   TSIOBuffer req_buffer;
131   TSIOBufferReader req_reader;
132 
133   TSVIO write_vio;
134   TSIOBuffer resp_buffer;
135   TSIOBufferReader resp_reader;
136 
137   char *request;
138   char response[RESPONSE_MAX_SIZE + 1];
139   int response_len;
140 
141   RequestStatus status;
142 
143   int connect_port;
144   int local_port;
145   uint64_t connect_ip;
146   TSAction connect_action;
147 
148   TxnHandler current_handler;
149 
150   unsigned int magic;
151 };
152 
153 //////////////////////////////////////////////////////////////////////////////
154 // DECLARATIONS
155 //////////////////////////////////////////////////////////////////////////////
156 
157 /* utility */
158 static char *get_body_ptr(const char *request);
159 static char *generate_request(int test_case);
160 static char *generate_response(const char *request);
161 static int get_request_id(TSHttpTxn txnp);
162 
163 /* client side */
164 static ClientTxn *synclient_txn_create();
165 static int synclient_txn_delete(ClientTxn *txn);
166 static void synclient_txn_close(ClientTxn *txn);
167 static int synclient_txn_send_request(ClientTxn *txn, char *request);
168 static int synclient_txn_send_request_to_vc(ClientTxn *txn, char *request, TSVConn vc);
169 static int synclient_txn_read_response(TSCont contp);
170 static int synclient_txn_read_response_handler(TSCont contp, TSEvent event, void *data);
171 static int synclient_txn_write_request(TSCont contp);
172 static int synclient_txn_write_request_handler(TSCont contp, TSEvent event, void *data);
173 static int synclient_txn_connect_handler(TSCont contp, TSEvent event, void *data);
174 static int synclient_txn_main_handler(TSCont contp, TSEvent event, void *data);
175 
176 /* Server side */
177 SocketServer *synserver_create(int port);
178 static int synserver_start(SocketServer *s);
179 static int synserver_stop(SocketServer *s);
180 static int synserver_delete(SocketServer *s);
181 static int synserver_vc_accept(TSCont contp, TSEvent event, void *data);
182 static int synserver_vc_refuse(TSCont contp, TSEvent event, void *data);
183 static int synserver_txn_close(TSCont contp);
184 static int synserver_txn_write_response(TSCont contp);
185 static int synserver_txn_write_response_handler(TSCont contp, TSEvent event, void *data);
186 static int synserver_txn_read_request(TSCont contp);
187 static int synserver_txn_read_request_handler(TSCont contp, TSEvent event, void *data);
188 static int synserver_txn_main_handler(TSCont contp, TSEvent event, void *data);
189 
190 //////////////////////////////////////////////////////////////////////////////
191 // REQUESTS/RESPONSES GENERATION
192 //////////////////////////////////////////////////////////////////////////////
193 
194 static char *
get_body_ptr(const char * request)195 get_body_ptr(const char *request)
196 {
197   char *ptr = const_cast<char *>(strstr(request, (const char *)"\r\n\r\n"));
198   return (ptr != nullptr) ? (ptr + 4) : nullptr;
199 }
200 
201 /* Caller must free returned request */
202 static char *
generate_request(int test_case)203 generate_request(int test_case)
204 {
205 // We define request formats.
206 // Each format has an X-Request-ID field that contains the id of the testcase
207 #define HTTP_REQUEST_DEFAULT_FORMAT                   \
208   "GET http://127.0.0.1:%d/default.html HTTP/1.0\r\n" \
209   "X-Request-ID: %d\r\n"                              \
210   "\r\n"
211 
212 #define HTTP_REQUEST_FORMAT1                          \
213   "GET http://127.0.0.1:%d/format1.html HTTP/1.0\r\n" \
214   "X-Request-ID: %d\r\n"                              \
215   "\r\n"
216 
217 #define HTTP_REQUEST_FORMAT2                          \
218   "GET http://127.0.0.1:%d/format2.html HTTP/1.0\r\n" \
219   "X-Request-ID: %d\r\n"                              \
220   "Content-Type: text/html\r\n"                       \
221   "\r\n"
222 #define HTTP_REQUEST_FORMAT3                          \
223   "GET http://127.0.0.1:%d/format3.html HTTP/1.0\r\n" \
224   "X-Request-ID: %d\r\n"                              \
225   "Response: Error\r\n"                               \
226   "\r\n"
227 #define HTTP_REQUEST_FORMAT4                          \
228   "GET http://127.0.0.1:%d/format4.html HTTP/1.0\r\n" \
229   "X-Request-ID: %d\r\n"                              \
230   "Request:%d\r\n"                                    \
231   "\r\n"
232 #define HTTP_REQUEST_FORMAT5                          \
233   "GET http://127.0.0.1:%d/format5.html HTTP/1.0\r\n" \
234   "X-Request-ID: %d\r\n"                              \
235   "Request:%d\r\n"                                    \
236   "\r\n"
237 #define HTTP_REQUEST_FORMAT6                         \
238   "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
239   "X-Request-ID: %d\r\n"                             \
240   "Accept-Language: English\r\n"                     \
241   "\r\n"
242 #define HTTP_REQUEST_FORMAT7                         \
243   "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
244   "X-Request-ID: %d\r\n"                             \
245   "Accept-Language: French\r\n"                      \
246   "\r\n"
247 #define HTTP_REQUEST_FORMAT8                         \
248   "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
249   "X-Request-ID: %d\r\n"                             \
250   "Accept-Language: English,French\r\n"              \
251   "\r\n"
252 #define HTTP_REQUEST_FORMAT9                                      \
253   "GET http://trafficserver.apache.org/format9.html HTTP/1.0\r\n" \
254   "X-Request-ID: %d\r\n"                                          \
255   "\r\n"
256 #define HTTP_REQUEST_FORMAT10                                      \
257   "GET http://trafficserver.apache.org/format10.html HTTP/1.0\r\n" \
258   "X-Request-ID: %d\r\n"                                           \
259   "\r\n"
260 #define HTTP_REQUEST_FORMAT11                                      \
261   "GET http://trafficserver.apache.org/format11.html HTTP/1.0\r\n" \
262   "X-Request-ID: %d\r\n"                                           \
263   "\r\n"
264   char *request = static_cast<char *>(TSmalloc(REQUEST_MAX_SIZE + 1));
265 
266   switch (test_case) {
267   case 1:
268     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT1, SYNSERVER_LISTEN_PORT, test_case);
269     break;
270   case 2:
271     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT2, SYNSERVER_LISTEN_PORT, test_case);
272     break;
273   case 3:
274     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT3, SYNSERVER_LISTEN_PORT, test_case);
275     break;
276   case 4:
277     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT4, SYNSERVER_LISTEN_PORT, test_case, 1);
278     break;
279   case 5:
280     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT5, SYNSERVER_LISTEN_PORT, test_case, 2);
281     break;
282   case 6:
283     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT6, SYNSERVER_LISTEN_PORT, test_case);
284     break;
285   case 7:
286     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT7, SYNSERVER_LISTEN_PORT, test_case - 1);
287     break;
288   case 8:
289     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT8, SYNSERVER_LISTEN_PORT, test_case - 2);
290     break;
291   case 9:
292     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT9, test_case);
293     break;
294   case 10:
295     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT10, test_case);
296     break;
297   case 11:
298     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT11, test_case);
299     break;
300   default:
301     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_DEFAULT_FORMAT, SYNSERVER_LISTEN_PORT, test_case);
302     break;
303   }
304 
305   return request;
306 }
307 
308 /* Caller must free returned response */
309 static char *
generate_response(const char * request)310 generate_response(const char *request)
311 {
312 // define format for response
313 // Each response contains a field X-Response-ID that contains the id of the testcase
314 #define HTTP_REQUEST_TESTCASE_FORMAT \
315   "GET %1024s HTTP/1.%d\r\n"         \
316   "X-Request-ID: %d\r\n"
317 
318 #define HTTP_RESPONSE_DEFAULT_FORMAT \
319   "HTTP/1.0 200 OK\r\n"              \
320   "X-Response-ID: %d\r\n"            \
321   "Cache-Control: max-age=86400\r\n" \
322   "Content-Type: text/html\r\n"      \
323   "\r\n"                             \
324   "Default body"
325 
326 #define HTTP_RESPONSE_FORMAT1   \
327   "HTTP/1.0 200 OK\r\n"         \
328   "X-Response-ID: %d\r\n"       \
329   "Content-Type: text/html\r\n" \
330   "Cache-Control: no-cache\r\n" \
331   "\r\n"                        \
332   "Body for response 1"
333 
334 #define HTTP_RESPONSE_FORMAT2        \
335   "HTTP/1.0 200 OK\r\n"              \
336   "X-Response-ID: %d\r\n"            \
337   "Cache-Control: max-age=86400\r\n" \
338   "Content-Type: text/html\r\n"      \
339   "\r\n"                             \
340   "Body for response 2"
341 #define HTTP_RESPONSE_FORMAT4        \
342   "HTTP/1.0 200 OK\r\n"              \
343   "X-Response-ID: %d\r\n"            \
344   "Cache-Control: max-age=86400\r\n" \
345   "Content-Type: text/html\r\n"      \
346   "\r\n"                             \
347   "Body for response 4"
348 #define HTTP_RESPONSE_FORMAT5   \
349   "HTTP/1.0 200 OK\r\n"         \
350   "X-Response-ID: %d\r\n"       \
351   "Content-Type: text/html\r\n" \
352   "\r\n"                        \
353   "Body for response 5"
354 #define HTTP_RESPONSE_FORMAT6        \
355   "HTTP/1.0 200 OK\r\n"              \
356   "X-Response-ID: %d\r\n"            \
357   "Cache-Control: max-age=86400\r\n" \
358   "Content-Language: English\r\n"    \
359   "\r\n"                             \
360   "Body for response 6"
361 #define HTTP_RESPONSE_FORMAT7        \
362   "HTTP/1.0 200 OK\r\n"              \
363   "X-Response-ID: %d\r\n"            \
364   "Cache-Control: max-age=86400\r\n" \
365   "Content-Language: French\r\n"     \
366   "\r\n"                             \
367   "Body for response 7"
368 
369 #define HTTP_RESPONSE_FORMAT8             \
370   "HTTP/1.0 200 OK\r\n"                   \
371   "X-Response-ID: %d\r\n"                 \
372   "Cache-Control: max-age=86400\r\n"      \
373   "Content-Language: French, English\r\n" \
374   "\r\n"                                  \
375   "Body for response 8"
376 
377 #define HTTP_RESPONSE_FORMAT9        \
378   "HTTP/1.0 200 OK\r\n"              \
379   "Cache-Control: max-age=86400\r\n" \
380   "X-Response-ID: %d\r\n"            \
381   "\r\n"                             \
382   "Body for response 9"
383 
384 #define HTTP_RESPONSE_FORMAT10       \
385   "HTTP/1.0 200 OK\r\n"              \
386   "Cache-Control: max-age=86400\r\n" \
387   "X-Response-ID: %d\r\n"            \
388   "\r\n"                             \
389   "Body for response 10"
390 
391 #define HTTP_RESPONSE_FORMAT11          \
392   "HTTP/1.0 200 OK\r\n"                 \
393   "Cache-Control: private,no-store\r\n" \
394   "X-Response-ID: %d\r\n"               \
395   "\r\n"                                \
396   "Body for response 11"
397 
398   int test_case, match, http_version;
399 
400   char *response = static_cast<char *>(TSmalloc(RESPONSE_MAX_SIZE + 1));
401   char url[1025];
402 
403   // coverity[secure_coding]
404   match = sscanf(request, HTTP_REQUEST_TESTCASE_FORMAT, url, &http_version, &test_case);
405   if (match == 3) {
406     switch (test_case) {
407     case 1:
408       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT1, test_case);
409       break;
410     case 2:
411       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT2, test_case);
412       break;
413     case 4:
414       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT4, test_case);
415       break;
416     case 5:
417       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT5, test_case);
418       break;
419     case 6:
420       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT6, test_case);
421       break;
422     case 7:
423       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT7, test_case);
424       break;
425     case 8:
426       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT8, test_case);
427       break;
428     case 9:
429       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT9, test_case);
430       break;
431     case 10:
432       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT10, test_case);
433       break;
434     case 11:
435       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT11, test_case);
436       break;
437     default:
438       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_DEFAULT_FORMAT, test_case);
439       break;
440     }
441   } else {
442     /* Didn't recognize a testcase request. send the default response */
443     snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_DEFAULT_FORMAT, test_case);
444   }
445 
446   return response;
447 }
448 
449 static int
get_request_id_value(const char * name,TSMBuffer buf,TSMLoc hdr)450 get_request_id_value(const char *name, TSMBuffer buf, TSMLoc hdr)
451 {
452   int id = -1;
453   TSMLoc field;
454 
455   field = TSMimeHdrFieldFind(buf, hdr, name, -1);
456   if (field != TS_NULL_MLOC) {
457     id = TSMimeHdrFieldValueIntGet(buf, hdr, field, 0);
458   }
459 
460   TSHandleMLocRelease(buf, hdr, field);
461   return id;
462 }
463 
464 // This routine can be called by tests, from the READ_REQUEST_HDR_HOOK
465 // to figure out the id of a test message
466 // Returns id/-1 in case of error
467 static int
get_request_id(TSHttpTxn txnp)468 get_request_id(TSHttpTxn txnp)
469 {
470   TSMBuffer bufp;
471   TSMLoc hdr_loc;
472   int id = -1;
473 
474   if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
475     return -1;
476   }
477 
478   id = get_request_id_value(X_REQUEST_ID, bufp, hdr_loc);
479   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
480   return id;
481 }
482 
483 // This routine can be called by tests, from the READ_RESPONSE_HDR_HOOK
484 // to figure out the id of a test message
485 // Returns id/-1 in case of error
486 static int
get_response_id(TSHttpTxn txnp)487 get_response_id(TSHttpTxn txnp)
488 {
489   TSMBuffer bufp;
490   TSMLoc hdr_loc;
491   int id = -1;
492 
493   if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
494     return -1;
495   }
496 
497   id = get_request_id_value(X_RESPONSE_ID, bufp, hdr_loc);
498   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
499   return id;
500 }
501 
502 //////////////////////////////////////////////////////////////////////////////
503 // SOCKET CLIENT
504 //////////////////////////////////////////////////////////////////////////////
505 
506 static ClientTxn *
synclient_txn_create()507 synclient_txn_create()
508 {
509   const HttpProxyPort *proxy_port;
510 
511   ClientTxn *txn = static_cast<ClientTxn *>(TSmalloc(sizeof(ClientTxn)));
512 
513   ink_zero(*txn);
514 
515   if (nullptr == (proxy_port = HttpProxyPort::findHttp(AF_INET))) {
516     txn->connect_port = PROXY_HTTP_DEFAULT_PORT;
517   } else {
518     txn->connect_port = proxy_port->m_port;
519   }
520 
521   txn->connect_ip = IP(127, 0, 0, 1);
522   txn->status     = REQUEST_INPROGRESS;
523   txn->magic      = MAGIC_ALIVE;
524 
525   TSDebug(CDBG_TAG, "Connecting to proxy 127.0.0.1 on port %d", txn->connect_port);
526   return txn;
527 }
528 
529 static int
synclient_txn_delete(ClientTxn * txn)530 synclient_txn_delete(ClientTxn *txn)
531 {
532   TSAssert(txn->magic == MAGIC_ALIVE);
533   if (txn->connect_action && !TSActionDone(txn->connect_action)) {
534     TSActionCancel(txn->connect_action);
535     txn->connect_action = nullptr;
536   }
537 
538   ats_free(txn->request);
539   txn->magic = MAGIC_DEAD;
540   TSfree(txn);
541   return 1;
542 }
543 
544 static void
synclient_txn_close(ClientTxn * txn)545 synclient_txn_close(ClientTxn *txn)
546 {
547   if (txn) {
548     if (txn->vconn != nullptr) {
549       TSVConnClose(txn->vconn);
550       txn->vconn = nullptr;
551     }
552 
553     if (txn->req_buffer != nullptr) {
554       TSIOBufferDestroy(txn->req_buffer);
555       txn->req_buffer = nullptr;
556     }
557 
558     if (txn->resp_buffer != nullptr) {
559       TSIOBufferDestroy(txn->resp_buffer);
560       txn->resp_buffer = nullptr;
561     }
562 
563     TSDebug(CDBG_TAG, "Client Txn destroyed");
564   }
565 }
566 
567 static int
synclient_txn_send_request(ClientTxn * txn,char * request)568 synclient_txn_send_request(ClientTxn *txn, char *request)
569 {
570   TSCont cont;
571   sockaddr_in addr;
572 
573   TSAssert(txn->magic == MAGIC_ALIVE);
574   txn->request = ats_strdup(request);
575   SET_TEST_HANDLER(txn->current_handler, synclient_txn_connect_handler);
576 
577   cont = TSContCreate(synclient_txn_main_handler, TSMutexCreate());
578   TSContDataSet(cont, txn);
579 
580   ats_ip4_set(&addr, txn->connect_ip, htons(txn->connect_port));
581   TSNetConnect(cont, ats_ip_sa_cast(&addr));
582   return 1;
583 }
584 
585 /* This can be used to send a request to a specific VC */
586 static int
synclient_txn_send_request_to_vc(ClientTxn * txn,char * request,TSVConn vc)587 synclient_txn_send_request_to_vc(ClientTxn *txn, char *request, TSVConn vc)
588 {
589   TSCont cont;
590   TSAssert(txn->magic == MAGIC_ALIVE);
591   txn->request = ats_strdup(request);
592   SET_TEST_HANDLER(txn->current_handler, synclient_txn_connect_handler);
593 
594   cont = TSContCreate(synclient_txn_main_handler, TSMutexCreate());
595   TSContDataSet(cont, txn);
596 
597   TSContCall(cont, TS_EVENT_NET_CONNECT, vc);
598   return 1;
599 }
600 
601 static int
synclient_txn_read_response(TSCont contp)602 synclient_txn_read_response(TSCont contp)
603 {
604   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
605   TSAssert(txn->magic == MAGIC_ALIVE);
606 
607   TSIOBufferBlock block = TSIOBufferReaderStart(txn->resp_reader);
608   while (block != nullptr) {
609     int64_t blocklen;
610     const char *blockptr = TSIOBufferBlockReadStart(block, txn->resp_reader, &blocklen);
611 
612     if (txn->response_len + blocklen <= RESPONSE_MAX_SIZE) {
613       memcpy((txn->response + txn->response_len), blockptr, blocklen);
614       txn->response_len += blocklen;
615     } else {
616       TSError("Error: Response length %" PRId64 " > response buffer size %d", txn->response_len + blocklen, RESPONSE_MAX_SIZE);
617     }
618 
619     block = TSIOBufferBlockNext(block);
620   }
621 
622   txn->response[txn->response_len] = '\0';
623   TSDebug(CDBG_TAG, "Response = |%s|, req len = %d", txn->response, txn->response_len);
624 
625   return 1;
626 }
627 
628 static int
synclient_txn_read_response_handler(TSCont contp,TSEvent event,void *)629 synclient_txn_read_response_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
630 {
631   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
632   TSAssert(txn->magic == MAGIC_ALIVE);
633 
634   int64_t avail;
635 
636   switch (event) {
637   case TS_EVENT_VCONN_READ_READY:
638   case TS_EVENT_VCONN_READ_COMPLETE:
639     if (event == TS_EVENT_VCONN_READ_READY) {
640       TSDebug(CDBG_TAG, "READ_READY");
641     } else {
642       TSDebug(CDBG_TAG, "READ_COMPLETE");
643     }
644 
645     avail = TSIOBufferReaderAvail(txn->resp_reader);
646     TSDebug(CDBG_TAG, "%" PRId64 " bytes available in buffer", avail);
647 
648     if (avail > 0) {
649       synclient_txn_read_response(contp);
650       TSIOBufferReaderConsume(txn->resp_reader, avail);
651     }
652 
653     TSVIOReenable(txn->read_vio);
654     break;
655 
656   case TS_EVENT_VCONN_EOS:
657     TSDebug(CDBG_TAG, "READ_EOS");
658     // Connection closed. In HTTP/1.0 it means we're done for this request.
659     txn->status = REQUEST_SUCCESS;
660     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
661     TSContDestroy(contp);
662     return 1;
663 
664   case TS_EVENT_ERROR:
665     TSDebug(CDBG_TAG, "READ_ERROR");
666     txn->status = REQUEST_FAILURE;
667     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
668     TSContDestroy(contp);
669     return 1;
670 
671   default:
672     TSAssert(!"Invalid event");
673     break;
674   }
675   return 1;
676 }
677 
678 static int
synclient_txn_write_request(TSCont contp)679 synclient_txn_write_request(TSCont contp)
680 {
681   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
682   TSAssert(txn->magic == MAGIC_ALIVE);
683 
684   TSIOBufferBlock block;
685   char *ptr_block;
686   int64_t len, ndone, ntodo, towrite, avail;
687 
688   len = strlen(txn->request);
689 
690   ndone = 0;
691   ntodo = len;
692   while (ntodo > 0) {
693     block     = TSIOBufferStart(txn->req_buffer);
694     ptr_block = TSIOBufferBlockWriteStart(block, &avail);
695     towrite   = std::min(ntodo, avail);
696     memcpy(ptr_block, txn->request + ndone, towrite);
697     TSIOBufferProduce(txn->req_buffer, towrite);
698     ntodo -= towrite;
699     ndone += towrite;
700   }
701 
702   /* Start writing the response */
703   TSDebug(CDBG_TAG, "Writing |%s| (%" PRId64 ") bytes", txn->request, len);
704   txn->write_vio = TSVConnWrite(txn->vconn, contp, txn->req_reader, len);
705 
706   return 1;
707 }
708 
709 static int
synclient_txn_write_request_handler(TSCont contp,TSEvent event,void *)710 synclient_txn_write_request_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
711 {
712   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
713   TSAssert(txn->magic == MAGIC_ALIVE);
714 
715   switch (event) {
716   case TS_EVENT_VCONN_WRITE_READY:
717     TSDebug(CDBG_TAG, "WRITE_READY");
718     TSVIOReenable(txn->write_vio);
719     break;
720 
721   case TS_EVENT_VCONN_WRITE_COMPLETE:
722     TSDebug(CDBG_TAG, "WRITE_COMPLETE");
723     // Weird: synclient should not close the write part of vconn.
724     // Otherwise some strangeness...
725 
726     /* Start reading */
727     SET_TEST_HANDLER(txn->current_handler, synclient_txn_read_response_handler);
728     txn->read_vio = TSVConnRead(txn->vconn, contp, txn->resp_buffer, INT64_MAX);
729     break;
730 
731   case TS_EVENT_VCONN_EOS:
732     TSDebug(CDBG_TAG, "WRITE_EOS");
733     txn->status = REQUEST_FAILURE;
734     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
735     TSContDestroy(contp);
736     break;
737 
738   case TS_EVENT_ERROR:
739     TSDebug(CDBG_TAG, "WRITE_ERROR");
740     txn->status = REQUEST_FAILURE;
741     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
742     TSContDestroy(contp);
743     break;
744 
745   default:
746     TSAssert(!"Invalid event");
747     break;
748   }
749   return TS_EVENT_IMMEDIATE;
750 }
751 
752 static int
synclient_txn_connect_handler(TSCont contp,TSEvent event,void * data)753 synclient_txn_connect_handler(TSCont contp, TSEvent event, void *data)
754 {
755   TSAssert((event == TS_EVENT_NET_CONNECT) || (event == TS_EVENT_NET_CONNECT_FAILED));
756 
757   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
758   TSAssert(txn->magic == MAGIC_ALIVE);
759 
760   if (event == TS_EVENT_NET_CONNECT) {
761     TSDebug(CDBG_TAG, "NET_CONNECT");
762 
763     txn->req_buffer  = TSIOBufferCreate();
764     txn->req_reader  = TSIOBufferReaderAlloc(txn->req_buffer);
765     txn->resp_buffer = TSIOBufferCreate();
766     txn->resp_reader = TSIOBufferReaderAlloc(txn->resp_buffer);
767 
768     txn->response[0]  = '\0';
769     txn->response_len = 0;
770 
771     txn->vconn      = static_cast<TSVConn>(data);
772     txn->local_port = (int)((NetVConnection *)data)->get_local_port();
773 
774     txn->write_vio = nullptr;
775     txn->read_vio  = nullptr;
776 
777     /* start writing */
778     SET_TEST_HANDLER(txn->current_handler, synclient_txn_write_request_handler);
779     synclient_txn_write_request(contp);
780 
781     return TS_EVENT_IMMEDIATE;
782   } else {
783     TSDebug(CDBG_TAG, "NET_CONNECT_FAILED");
784     txn->status = REQUEST_FAILURE;
785     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
786     TSContDestroy(contp);
787   }
788 
789   return TS_EVENT_IMMEDIATE;
790 }
791 
792 static int
synclient_txn_main_handler(TSCont contp,TSEvent event,void * data)793 synclient_txn_main_handler(TSCont contp, TSEvent event, void *data)
794 {
795   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
796   TSAssert(txn->magic == MAGIC_ALIVE);
797 
798   TxnHandler handler = txn->current_handler;
799   return (*handler)(contp, event, data);
800 }
801 
802 //////////////////////////////////////////////////////////////////////////////
803 // SOCKET SERVER
804 //////////////////////////////////////////////////////////////////////////////
805 
806 SocketServer *
synserver_create(int port,TSCont cont)807 synserver_create(int port, TSCont cont)
808 {
809   if (port != SYNSERVER_DUMMY_PORT) {
810     TSAssert(port > 0);
811     TSAssert(port < INT16_MAX);
812   }
813 
814   SocketServer *s  = static_cast<SocketServer *>(TSmalloc(sizeof(SocketServer)));
815   s->magic         = MAGIC_ALIVE;
816   s->accept_port   = port;
817   s->accept_action = nullptr;
818   s->accept_cont   = cont;
819   TSContDataSet(s->accept_cont, s);
820   return s;
821 }
822 
823 SocketServer *
synserver_create(int port)824 synserver_create(int port)
825 {
826   return synserver_create(port, TSContCreate(synserver_vc_accept, TSMutexCreate()));
827 }
828 
829 static int
synserver_start(SocketServer * s)830 synserver_start(SocketServer *s)
831 {
832   TSAssert(s->magic == MAGIC_ALIVE);
833   TSAssert(s->accept_action == nullptr);
834 
835   if (s->accept_port != SYNSERVER_DUMMY_PORT) {
836     TSAssert(s->accept_port > 0);
837     TSAssert(s->accept_port < INT16_MAX);
838 
839     s->accept_action = TSNetAccept(s->accept_cont, s->accept_port, AF_INET, 0);
840   }
841 
842   return 1;
843 }
844 
845 static int
synserver_stop(SocketServer * s)846 synserver_stop(SocketServer *s)
847 {
848   TSAssert(s->magic == MAGIC_ALIVE);
849   if (s->accept_action && !TSActionDone(s->accept_action)) {
850     TSActionCancel(s->accept_action);
851     s->accept_action = nullptr;
852     TSDebug(SDBG_TAG, "Had to cancel action");
853   }
854   TSDebug(SDBG_TAG, "stopped");
855   return 1;
856 }
857 
858 static int
synserver_delete(SocketServer * s)859 synserver_delete(SocketServer *s)
860 {
861   if (s != nullptr) {
862     TSAssert(s->magic == MAGIC_ALIVE);
863     synserver_stop(s);
864 
865     if (s->accept_cont) {
866       TSContDestroy(s->accept_cont);
867       s->accept_cont = nullptr;
868       TSDebug(SDBG_TAG, "destroyed accept cont");
869     }
870 
871     s->magic = MAGIC_DEAD;
872     TSfree(s);
873     TSDebug(SDBG_TAG, "deleted server");
874   }
875 
876   return 1;
877 }
878 
879 static int
synserver_vc_refuse(TSCont contp,TSEvent event,void * data)880 synserver_vc_refuse(TSCont contp, TSEvent event, void *data)
881 {
882   TSAssert((event == TS_EVENT_NET_ACCEPT) || (event == TS_EVENT_NET_ACCEPT_FAILED));
883 
884   SocketServer *s = static_cast<SocketServer *>(TSContDataGet(contp));
885   TSAssert(s->magic == MAGIC_ALIVE);
886 
887   TSDebug(SDBG_TAG, "%s: NET_ACCEPT", __func__);
888 
889   if (event == TS_EVENT_NET_ACCEPT_FAILED) {
890     Warning("Synserver failed to bind to port %d.", ntohs(s->accept_port));
891     ink_release_assert(!"Synserver must be able to bind to a port, check system netstat");
892     TSDebug(SDBG_TAG, "%s: NET_ACCEPT_FAILED", __func__);
893     return TS_EVENT_IMMEDIATE;
894   }
895 
896   TSVConnClose(static_cast<TSVConn>(data));
897   return TS_EVENT_IMMEDIATE;
898 }
899 
900 static int
synserver_vc_accept(TSCont contp,TSEvent event,void * data)901 synserver_vc_accept(TSCont contp, TSEvent event, void *data)
902 {
903   TSAssert((event == TS_EVENT_NET_ACCEPT) || (event == TS_EVENT_NET_ACCEPT_FAILED));
904 
905   SocketServer *s = static_cast<SocketServer *>(TSContDataGet(contp));
906   TSAssert(s->magic == MAGIC_ALIVE);
907 
908   if (event == TS_EVENT_NET_ACCEPT_FAILED) {
909     Warning("Synserver failed to bind to port %d.", ntohs(s->accept_port));
910     ink_release_assert(!"Synserver must be able to bind to a port, check system netstat");
911     TSDebug(SDBG_TAG, "%s: NET_ACCEPT_FAILED", __func__);
912     return TS_EVENT_IMMEDIATE;
913   }
914 
915   TSDebug(SDBG_TAG, "%s: NET_ACCEPT", __func__);
916 
917   /* Create a new transaction */
918   ServerTxn *txn = static_cast<ServerTxn *>(TSmalloc(sizeof(ServerTxn)));
919   txn->magic     = MAGIC_ALIVE;
920 
921   SET_TEST_HANDLER(txn->current_handler, synserver_txn_read_request_handler);
922 
923   TSCont txn_cont = TSContCreate(synserver_txn_main_handler, TSMutexCreate());
924   TSContDataSet(txn_cont, txn);
925 
926   txn->req_buffer = TSIOBufferCreate();
927   txn->req_reader = TSIOBufferReaderAlloc(txn->req_buffer);
928 
929   txn->resp_buffer = TSIOBufferCreate();
930   txn->resp_reader = TSIOBufferReaderAlloc(txn->resp_buffer);
931 
932   txn->request[0]  = '\0';
933   txn->request_len = 0;
934 
935   txn->vconn = static_cast<TSVConn>(data);
936 
937   txn->write_vio = nullptr;
938 
939   /* start reading */
940   txn->read_vio = TSVConnRead(txn->vconn, txn_cont, txn->req_buffer, INT64_MAX);
941 
942   return TS_EVENT_IMMEDIATE;
943 }
944 
945 static int
synserver_txn_close(TSCont contp)946 synserver_txn_close(TSCont contp)
947 {
948   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
949   TSAssert(txn->magic == MAGIC_ALIVE);
950 
951   if (txn->vconn != nullptr) {
952     TSVConnClose(txn->vconn);
953   }
954   if (txn->req_buffer) {
955     TSIOBufferDestroy(txn->req_buffer);
956   }
957   if (txn->resp_buffer) {
958     TSIOBufferDestroy(txn->resp_buffer);
959   }
960 
961   txn->magic = MAGIC_DEAD;
962   TSfree(txn);
963   TSContDestroy(contp);
964 
965   TSDebug(SDBG_TAG, "Server Txn destroyed");
966   return TS_EVENT_IMMEDIATE;
967 }
968 
969 static int
synserver_txn_write_response(TSCont contp)970 synserver_txn_write_response(TSCont contp)
971 {
972   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
973   TSAssert(txn->magic == MAGIC_ALIVE);
974 
975   SET_TEST_HANDLER(txn->current_handler, synserver_txn_write_response_handler);
976 
977   TSIOBufferBlock block;
978   char *ptr_block;
979   int64_t len, ndone, ntodo, towrite, avail;
980   char *response;
981 
982   response = generate_response(txn->request);
983   len      = strlen(response);
984 
985   ndone = 0;
986   ntodo = len;
987   while (ntodo > 0) {
988     block     = TSIOBufferStart(txn->resp_buffer);
989     ptr_block = TSIOBufferBlockWriteStart(block, &avail);
990     towrite   = std::min(ntodo, avail);
991     memcpy(ptr_block, response + ndone, towrite);
992     TSIOBufferProduce(txn->resp_buffer, towrite);
993     ntodo -= towrite;
994     ndone += towrite;
995   }
996 
997   /* Start writing the response */
998   TSDebug(SDBG_TAG, "Writing response: |%s| (%" PRId64 ") bytes)", response, len);
999   txn->write_vio = TSVConnWrite(txn->vconn, contp, txn->resp_reader, len);
1000 
1001   /* Now that response is in IOBuffer, free up response */
1002   TSfree(response);
1003 
1004   return TS_EVENT_IMMEDIATE;
1005 }
1006 
1007 static int
synserver_txn_write_response_handler(TSCont contp,TSEvent event,void *)1008 synserver_txn_write_response_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
1009 {
1010   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1011   TSAssert(txn->magic == MAGIC_ALIVE);
1012 
1013   switch (event) {
1014   case TS_EVENT_VCONN_WRITE_READY:
1015     TSDebug(SDBG_TAG, "WRITE_READY");
1016     TSVIOReenable(txn->write_vio);
1017     break;
1018 
1019   case TS_EVENT_VCONN_WRITE_COMPLETE:
1020     TSDebug(SDBG_TAG, "WRITE_COMPLETE");
1021     TSVConnShutdown(txn->vconn, 0, 1);
1022     return synserver_txn_close(contp);
1023     break;
1024 
1025   case TS_EVENT_VCONN_EOS:
1026     TSDebug(SDBG_TAG, "WRITE_EOS");
1027     return synserver_txn_close(contp);
1028     break;
1029 
1030   case TS_EVENT_ERROR:
1031     TSDebug(SDBG_TAG, "WRITE_ERROR");
1032     return synserver_txn_close(contp);
1033     break;
1034 
1035   default:
1036     TSAssert(!"Invalid event");
1037     break;
1038   }
1039   return TS_EVENT_IMMEDIATE;
1040 }
1041 
1042 static int
synserver_txn_read_request(TSCont contp)1043 synserver_txn_read_request(TSCont contp)
1044 {
1045   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1046   TSAssert(txn->magic == MAGIC_ALIVE);
1047 
1048   int end;
1049   TSIOBufferBlock block = TSIOBufferReaderStart(txn->req_reader);
1050 
1051   while (block != nullptr) {
1052     int64_t blocklen;
1053     const char *blockptr = TSIOBufferBlockReadStart(block, txn->req_reader, &blocklen);
1054 
1055     if (txn->request_len + blocklen <= REQUEST_MAX_SIZE) {
1056       memcpy((txn->request + txn->request_len), blockptr, blocklen);
1057       txn->request_len += blocklen;
1058     } else {
1059       TSError("Error: Request length %" PRId64 " > request buffer size %d", txn->request_len + blocklen, REQUEST_MAX_SIZE);
1060     }
1061 
1062     block = TSIOBufferBlockNext(block);
1063   }
1064 
1065   txn->request[txn->request_len] = '\0';
1066   TSDebug(SDBG_TAG, "Request = |%s|, req len = %d", txn->request, txn->request_len);
1067 
1068   end = (strstr(txn->request, HTTP_REQUEST_END) != nullptr);
1069   TSDebug(SDBG_TAG, "End of request = %d", end);
1070 
1071   return end;
1072 }
1073 
1074 static int
synserver_txn_read_request_handler(TSCont contp,TSEvent event,void *)1075 synserver_txn_read_request_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
1076 {
1077   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1078   TSAssert(txn->magic == MAGIC_ALIVE);
1079 
1080   int64_t avail;
1081   int end_of_request;
1082 
1083   switch (event) {
1084   case TS_EVENT_VCONN_READ_READY:
1085   case TS_EVENT_VCONN_READ_COMPLETE:
1086     TSDebug(SDBG_TAG, (event == TS_EVENT_VCONN_READ_READY) ? "READ_READY" : "READ_COMPLETE");
1087     avail = TSIOBufferReaderAvail(txn->req_reader);
1088     TSDebug(SDBG_TAG, "%" PRId64 " bytes available in buffer", avail);
1089 
1090     if (avail > 0) {
1091       end_of_request = synserver_txn_read_request(contp);
1092       TSIOBufferReaderConsume(txn->req_reader, avail);
1093 
1094       if (end_of_request) {
1095         TSVConnShutdown(txn->vconn, 1, 0);
1096         return synserver_txn_write_response(contp);
1097       }
1098     }
1099 
1100     TSVIOReenable(txn->read_vio);
1101     break;
1102 
1103   case TS_EVENT_VCONN_EOS:
1104     TSDebug(SDBG_TAG, "READ_EOS");
1105     return synserver_txn_close(contp);
1106     break;
1107 
1108   case TS_EVENT_ERROR:
1109     TSDebug(SDBG_TAG, "READ_ERROR");
1110     return synserver_txn_close(contp);
1111     break;
1112 
1113   default:
1114     TSAssert(!"Invalid event");
1115     break;
1116   }
1117   return TS_EVENT_IMMEDIATE;
1118 }
1119 
1120 static int
synserver_txn_main_handler(TSCont contp,TSEvent event,void * data)1121 synserver_txn_main_handler(TSCont contp, TSEvent event, void *data)
1122 {
1123   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1124   TSAssert(txn->magic == MAGIC_ALIVE);
1125 
1126   TxnHandler handler = txn->current_handler;
1127   return (*handler)(contp, event, data);
1128 }
1129 
1130 // End of the previous #include "InkAPITestTool.cc"
1131 
1132 #define TC_PASS 1
1133 #define TC_FAIL 0
1134 
1135 #define UTDBG_TAG "sdk_ut"
1136 
1137 // Since there's no way to unregister global hooks, tests that register a hook
1138 // have to co-operate once they are complete by re-enabling and transactions
1139 // and getting out of the way.
1140 #define CHECK_SPURIOUS_EVENT(cont, event, edata)                     \
1141   if (TSContDataGet(cont) == NULL) {                                 \
1142     switch (event) {                                                 \
1143     case TS_EVENT_IMMEDIATE:                                         \
1144     case TS_EVENT_TIMEOUT:                                           \
1145       return TS_EVENT_NONE;                                          \
1146     case TS_EVENT_HTTP_SELECT_ALT:                                   \
1147       return TS_EVENT_NONE;                                          \
1148     case TS_EVENT_HTTP_READ_REQUEST_HDR:                             \
1149     case TS_EVENT_HTTP_OS_DNS:                                       \
1150     case TS_EVENT_HTTP_SEND_REQUEST_HDR:                             \
1151     case TS_EVENT_HTTP_READ_CACHE_HDR:                               \
1152     case TS_EVENT_HTTP_READ_RESPONSE_HDR:                            \
1153     case TS_EVENT_HTTP_SEND_RESPONSE_HDR:                            \
1154     case TS_EVENT_HTTP_REQUEST_TRANSFORM:                            \
1155     case TS_EVENT_HTTP_RESPONSE_TRANSFORM:                           \
1156     case TS_EVENT_HTTP_TXN_START:                                    \
1157     case TS_EVENT_HTTP_TXN_CLOSE:                                    \
1158     case TS_EVENT_HTTP_SSN_START:                                    \
1159     case TS_EVENT_HTTP_SSN_CLOSE:                                    \
1160     case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:                        \
1161     case TS_EVENT_HTTP_PRE_REMAP:                                    \
1162     case TS_EVENT_HTTP_POST_REMAP:                                   \
1163       TSHttpTxnReenable((TSHttpTxn)(edata), TS_EVENT_HTTP_CONTINUE); \
1164       return TS_EVENT_NONE;                                          \
1165     default:                                                         \
1166       break;                                                         \
1167     }                                                                \
1168   }
1169 
1170 /******************************************************************************/
1171 
1172 /* Use SDK_RPRINT to report failure or success for each test case */
1173 int
SDK_RPRINT(RegressionTest * t,const char * api_name,const char * testcase_name,int status,const char * err_details_format,...)1174 SDK_RPRINT(RegressionTest *t, const char *api_name, const char *testcase_name, int status, const char *err_details_format, ...)
1175 {
1176   int l;
1177   char buffer[8192];
1178   char format2[8192];
1179   snprintf(format2, sizeof(format2), "[%s] %s : [%s] <<%s>> { %s }\n", t->name, api_name, testcase_name,
1180            status == TC_PASS ? "PASS" : "FAIL", err_details_format);
1181   va_list ap;
1182   va_start(ap, err_details_format);
1183   l = ink_bvsprintf(buffer, format2, ap);
1184   va_end(ap);
1185   fputs(buffer, stderr);
1186   return (l);
1187 }
1188 
1189 /*
1190   REGRESSION_TEST(SDK_<test_name>)(RegressionTest *t, int atype, int *pstatus)
1191 
1192   RegressionTest *test is a pointer on object that will run the test.
1193    Do not modify.
1194 
1195   int atype is one of:
1196    REGRESSION_TEST_NONE
1197    REGRESSION_TEST_QUICK
1198    REGRESSION_TEST_NIGHTLY
1199    REGRESSION_TEST_EXTENDED
1200 
1201   int *pstatus should be set to one of:
1202    REGRESSION_TEST_PASSED
1203    REGRESSION_TEST_INPROGRESS
1204    REGRESSION_TEST_FAILED
1205    REGRESSION_TEST_NOT_RUN
1206   Note: pstatus is polled and can be used for asynchronous tests.
1207 
1208 */
1209 
1210 /* Misc */
1211 ////////////////////////////////////////////////
1212 //       SDK_API_TSTrafficServerVersionGet
1213 //
1214 // Unit Test for API: TSTrafficServerVersionGet
1215 ////////////////////////////////////////////////
REGRESSION_TEST(SDK_API_TSTrafficServerVersionGet)1216 REGRESSION_TEST(SDK_API_TSTrafficServerVersionGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1217 {
1218   *pstatus = REGRESSION_TEST_INPROGRESS;
1219 
1220   /* Assume the UT runs on TS5.0 and higher */
1221   const char *ts_version = TSTrafficServerVersionGet();
1222   if (!ts_version) {
1223     SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase1", TC_FAIL, "can't get traffic server version");
1224     *pstatus = REGRESSION_TEST_FAILED;
1225     return;
1226   }
1227 
1228   int major_ts_version = 0;
1229   int minor_ts_version = 0;
1230   int patch_ts_version = 0;
1231   // coverity[secure_coding]
1232   if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
1233     SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase2", TC_FAIL, "traffic server version format is incorrect");
1234     *pstatus = REGRESSION_TEST_FAILED;
1235     return;
1236   }
1237 
1238   if (major_ts_version < 2) {
1239     SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase3", TC_FAIL, "traffic server major version is incorrect");
1240     *pstatus = REGRESSION_TEST_FAILED;
1241     return;
1242   }
1243 
1244   SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase1", TC_PASS, "ok");
1245   *pstatus = REGRESSION_TEST_PASSED;
1246   return;
1247 }
1248 
1249 ////////////////////////////////////////////////
1250 //       SDK_API_TSPluginDirGet
1251 //
1252 // Unit Test for API: TSPluginDirGet
1253 //                    TSInstallDirGet
1254 //                    TSRuntimeDirGet
1255 ////////////////////////////////////////////////
REGRESSION_TEST(SDK_API_TSPluginDirGet)1256 REGRESSION_TEST(SDK_API_TSPluginDirGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1257 {
1258   *pstatus = REGRESSION_TEST_INPROGRESS;
1259 
1260   const char *plugin_dir  = TSPluginDirGet();
1261   const char *install_dir = TSInstallDirGet();
1262   const char *runtime_dir = TSRuntimeDirGet();
1263 
1264   if (!plugin_dir) {
1265     SDK_RPRINT(test, "TSPluginDirGet", "TestCase1", TC_FAIL, "can't get plugin dir");
1266     *pstatus = REGRESSION_TEST_FAILED;
1267     return;
1268   }
1269 
1270   if (!install_dir) {
1271     SDK_RPRINT(test, "TSInstallDirGet", "TestCase1", TC_FAIL, "can't get installation dir");
1272     *pstatus = REGRESSION_TEST_FAILED;
1273     return;
1274   }
1275 
1276   if (!runtime_dir) {
1277     SDK_RPRINT(test, "TSRuntimeDirGet", "TestCase1", TC_FAIL, "can't get runtime dir");
1278     *pstatus = REGRESSION_TEST_FAILED;
1279     return;
1280   }
1281 
1282   if (strstr(plugin_dir, TS_BUILD_LIBEXECDIR) == nullptr) {
1283     SDK_RPRINT(test, "TSPluginDirGet", "TestCase2", TC_FAIL, "plugin dir(%s) is incorrect, expected (%s) in path.", plugin_dir,
1284                TS_BUILD_LIBEXECDIR);
1285     *pstatus = REGRESSION_TEST_FAILED;
1286     return;
1287   }
1288 
1289   if (strstr(plugin_dir, install_dir) == nullptr) {
1290     SDK_RPRINT(test, "TSInstallDirGet", "TestCase2", TC_FAIL, "install dir is incorrect");
1291     *pstatus = REGRESSION_TEST_FAILED;
1292     return;
1293   }
1294 
1295   if (strstr(runtime_dir, TS_BUILD_RUNTIMEDIR) == nullptr) {
1296     SDK_RPRINT(test, "TSRuntimeDirGet", "TestCase2", TC_FAIL, "runtime dir is incorrect");
1297     *pstatus = REGRESSION_TEST_FAILED;
1298     return;
1299   }
1300 
1301   SDK_RPRINT(test, "TSPluginDirGet", "TestCase1", TC_PASS, "ok");
1302   SDK_RPRINT(test, "TSInstallDirGet", "TestCase1", TC_PASS, "ok");
1303   SDK_RPRINT(test, "TSRuntimeDirGet", "TestCase1", TC_PASS, "ok");
1304   *pstatus = REGRESSION_TEST_PASSED;
1305   return;
1306 }
1307 
1308 /* TSConfig */
1309 ////////////////////////////////////////////////
1310 //       SDK_API_TSConfig
1311 //
1312 // Unit Test for API: TSConfigSet
1313 //                    TSConfigGet
1314 //                    TSConfigRelease
1315 //                    TSConfigDataGet
1316 ////////////////////////////////////////////////
1317 static int my_config_id = 0;
1318 struct ConfigData {
1319   const char *a;
1320   const char *b;
1321 };
1322 
REGRESSION_TEST(SDK_API_TSConfig)1323 REGRESSION_TEST(SDK_API_TSConfig)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1324 {
1325   *pstatus           = REGRESSION_TEST_INPROGRESS;
1326   ConfigData *config = new ConfigData;
1327   config->a          = "unit";
1328   config->b          = "test";
1329 
1330   my_config_id = TSConfigSet(my_config_id, config, [](void *cfg) { delete static_cast<ConfigData *>(cfg); });
1331 
1332   TSConfig test_config = nullptr;
1333   test_config          = TSConfigGet(my_config_id);
1334 
1335   if (!test_config) {
1336     SDK_RPRINT(test, "TSConfigSet", "TestCase1", TC_FAIL, "can't correctly set global config structure");
1337     SDK_RPRINT(test, "TSConfigGet", "TestCase1", TC_FAIL, "can't correctly get global config structure");
1338     TSConfigRelease(my_config_id, reinterpret_cast<TSConfig>(config));
1339     *pstatus = REGRESSION_TEST_FAILED;
1340     return;
1341   }
1342 
1343   if (TSConfigDataGet(test_config) != config) {
1344     SDK_RPRINT(test, "TSConfigDataGet", "TestCase1", TC_FAIL, "failed to get config data");
1345     TSConfigRelease(my_config_id, reinterpret_cast<TSConfig>(config));
1346     *pstatus = REGRESSION_TEST_FAILED;
1347     return;
1348   }
1349 
1350   SDK_RPRINT(test, "TSConfigGet", "TestCase1", TC_PASS, "ok");
1351   SDK_RPRINT(test, "TSConfigSet", "TestCase1", TC_PASS, "ok");
1352   SDK_RPRINT(test, "TSConfigDataGet", "TestCase1", TC_PASS, "ok");
1353 
1354   TSConfigRelease(my_config_id, reinterpret_cast<TSConfig>(config));
1355   *pstatus = REGRESSION_TEST_PASSED;
1356   return;
1357 }
1358 
1359 /* TSNetVConn */
1360 //////////////////////////////////////////////
1361 //       SDK_API_TSNetVConn
1362 //
1363 // Unit Test for API: TSNetVConnRemoteIPGet
1364 //                    TSNetVConnRemotePortGet
1365 //                    TSNetAccept
1366 //                    TSNetConnect
1367 //////////////////////////////////////////////
1368 
1369 struct SDK_NetVConn_Params {
SDK_NetVConn_ParamsSDK_NetVConn_Params1370   SDK_NetVConn_Params(const char *_a, RegressionTest *_t, int *_p)
1371     : buffer(nullptr), api(_a), port(0), test(_t), pstatus(_p), vc(nullptr)
1372   {
1373     this->status.client = this->status.server = REGRESSION_TEST_INPROGRESS;
1374   }
1375 
~SDK_NetVConn_ParamsSDK_NetVConn_Params1376   ~SDK_NetVConn_Params()
1377   {
1378     if (this->buffer) {
1379       TSIOBufferDestroy(this->buffer);
1380     }
1381     if (this->vc) {
1382       TSVConnClose(this->vc);
1383     }
1384   }
1385 
1386   TSIOBuffer buffer;
1387   const char *api;
1388   unsigned short port;
1389   RegressionTest *test;
1390   int *pstatus;
1391   TSVConn vc;
1392   struct {
1393     int client;
1394     int server;
1395   } status;
1396 };
1397 
1398 int
server_handler(TSCont contp,TSEvent event,void * data)1399 server_handler(TSCont contp, TSEvent event, void *data)
1400 {
1401   SDK_NetVConn_Params *params = static_cast<SDK_NetVConn_Params *>(TSContDataGet(contp));
1402 
1403   if (event == TS_EVENT_NET_ACCEPT) {
1404     // Kick off a read so that we can receive an EOS event.
1405     SDK_RPRINT(params->test, params->api, "ServerEvent NET_ACCEPT", TC_PASS, "ok");
1406     params->buffer = TSIOBufferCreate();
1407     params->vc     = static_cast<TSVConn>(data);
1408     TSVConnRead(static_cast<TSVConn>(data), contp, params->buffer, 100);
1409   } else if (event == TS_EVENT_VCONN_EOS) {
1410     // The server end of the test passes if it receives an EOF event. This means that it must have
1411     // connected to the endpoint. Since this always happens *after* the accept, we know that it is
1412     // safe to delete the params.
1413     TSContDestroy(contp);
1414 
1415     SDK_RPRINT(params->test, params->api, "ServerEvent EOS", TC_PASS, "ok");
1416     *params->pstatus = REGRESSION_TEST_PASSED;
1417     delete params;
1418   } else if (event == TS_EVENT_VCONN_READ_READY) {
1419     SDK_RPRINT(params->test, params->api, "ServerEvent READ_READY", TC_PASS, "ok");
1420   } else {
1421     SDK_RPRINT(params->test, params->api, "ServerEvent", TC_FAIL, "received unexpected event %d", event);
1422     *params->pstatus = REGRESSION_TEST_FAILED;
1423     delete params;
1424   }
1425 
1426   return 1;
1427 }
1428 
1429 int
client_handler(TSCont contp,TSEvent event,void * data)1430 client_handler(TSCont contp, TSEvent event, void *data)
1431 {
1432   SDK_NetVConn_Params *params = static_cast<SDK_NetVConn_Params *>(TSContDataGet(contp));
1433 
1434   if (event == TS_EVENT_NET_CONNECT_FAILED) {
1435     SDK_RPRINT(params->test, params->api, "ClientConnect", TC_FAIL, "can't connect to server");
1436 
1437     *params->pstatus = REGRESSION_TEST_FAILED;
1438 
1439     // no need to continue, return
1440     // Fix me: how to deal with server side cont?
1441     TSContDestroy(contp);
1442     return 1;
1443   } else if (TS_EVENT_NET_CONNECT == event) {
1444     sockaddr const *addr       = TSNetVConnRemoteAddrGet(static_cast<TSVConn>(data));
1445     uint16_t input_server_port = ats_ip_port_host_order(addr);
1446 
1447     // If DEFER_ACCEPT is enabled in the OS then the user space accept() doesn't
1448     // happen until data arrives on the socket. Because we're just testing the accept()
1449     // we write a small amount of ignored data to make sure this gets triggered.
1450     UnixNetVConnection *vc = static_cast<UnixNetVConnection *>(data);
1451     ink_release_assert(::write(vc->con.fd, "Bob's your uncle", 16) != 0);
1452 
1453     sleep(1); // XXX this sleep ensures the server end gets the accept event.
1454 
1455     if (ats_is_ip_loopback(addr)) {
1456       SDK_RPRINT(params->test, params->api, "TSNetVConnRemoteIPGet", TC_PASS, "ok");
1457     } else {
1458       ip_text_buffer s, ipb;
1459       IpEndpoint loopback;
1460       ats_ip4_set(&loopback, htonl(INADDR_LOOPBACK));
1461       SDK_RPRINT(params->test, params->api, "TSNetVConnRemoteIPGet", TC_FAIL, "server ip [%s] is incorrect - expected [%s]",
1462                  ats_ip_ntop(addr, s, sizeof s), ats_ip_ntop(&loopback.sa, ipb, sizeof ipb));
1463 
1464       TSContDestroy(contp);
1465       // Fix me: how to deal with server side cont?
1466       *params->pstatus = REGRESSION_TEST_FAILED;
1467       return 1;
1468     }
1469 
1470     if (input_server_port == params->port) {
1471       SDK_RPRINT(params->test, params->api, "TSNetVConnRemotePortGet", TC_PASS, "ok");
1472     } else {
1473       SDK_RPRINT(params->test, params->api, "TSNetVConnRemotePortGet", TC_FAIL, "server port [%d] is incorrect -- expected [%d]",
1474                  input_server_port, params->port);
1475 
1476       TSContDestroy(contp);
1477       // Fix me: how to deal with server side cont?
1478       *params->pstatus = REGRESSION_TEST_FAILED;
1479       return 1;
1480     }
1481 
1482     SDK_RPRINT(params->test, params->api, "TSNetConnect", TC_PASS, "ok");
1483 
1484     // XXX We really ought to do a write/read exchange with the server. The sleep above works around this.
1485 
1486     // Looks good from the client end. Next we disconnect so that the server end can set the final test status.
1487     TSVConnClose(static_cast<TSVConn>(data));
1488   }
1489 
1490   TSContDestroy(contp);
1491 
1492   return 1;
1493 }
1494 
REGRESSION_TEST(SDK_API_TSNetVConn)1495 REGRESSION_TEST(SDK_API_TSNetVConn)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1496 {
1497   *pstatus = REGRESSION_TEST_INPROGRESS;
1498 
1499   SDK_NetVConn_Params *params = new SDK_NetVConn_Params("TSNetAccept", test, pstatus);
1500 
1501   params->port = 12345;
1502 
1503   TSCont server_cont = TSContCreate(server_handler, TSMutexCreate());
1504   TSCont client_cont = TSContCreate(client_handler, TSMutexCreate());
1505 
1506   TSContDataSet(server_cont, params);
1507   TSContDataSet(client_cont, params);
1508 
1509   TSNetAccept(server_cont, params->port, -1, 0);
1510 
1511   IpEndpoint addr;
1512   ats_ip4_set(&addr, htonl(INADDR_LOOPBACK), htons(params->port));
1513   TSNetConnect(client_cont, &addr.sa);
1514 }
1515 
REGRESSION_TEST(SDK_API_TSPortDescriptor)1516 REGRESSION_TEST(SDK_API_TSPortDescriptor)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1517 {
1518   *pstatus = REGRESSION_TEST_INPROGRESS;
1519 
1520   TSPortDescriptor port;
1521   char desc[64];
1522   SDK_NetVConn_Params *params = new SDK_NetVConn_Params("TSPortDescriptorAccept", test, pstatus);
1523   TSCont server_cont          = TSContCreate(server_handler, TSMutexCreate());
1524   TSCont client_cont          = TSContCreate(client_handler, TSMutexCreate());
1525 
1526   params->port = 54321;
1527 
1528   TSContDataSet(server_cont, params);
1529   TSContDataSet(client_cont, params);
1530 
1531   port = TSPortDescriptorParse(nullptr);
1532   if (port) {
1533     SDK_RPRINT(test, "TSPortDescriptorParse", "NULL port descriptor", TC_FAIL, "TSPortDescriptorParse(NULL) returned %s", port);
1534     *pstatus = REGRESSION_TEST_FAILED;
1535     return;
1536   }
1537 
1538   snprintf(desc, sizeof(desc), "%u", params->port);
1539   port = TSPortDescriptorParse(desc);
1540 
1541   if (TSPortDescriptorAccept(port, server_cont) == TS_ERROR) {
1542     SDK_RPRINT(test, "TSPortDescriptorParse", "Basic port descriptor", TC_FAIL, "TSPortDescriptorParse(%s) returned TS_ERROR",
1543                desc);
1544     *pstatus = REGRESSION_TEST_FAILED;
1545     return;
1546   }
1547 
1548   IpEndpoint addr;
1549   ats_ip4_set(&addr, htonl(INADDR_LOOPBACK), htons(params->port));
1550   TSNetConnect(client_cont, &addr.sa);
1551 }
1552 
1553 /* TSCache, TSVConn, TSVIO */
1554 //////////////////////////////////////////////
1555 //       SDK_API_TSCache
1556 //
1557 // Unit Test for API: TSCacheReady
1558 //                    TSCacheWrite
1559 //                    TSCacheRead
1560 //                    TSCacheKeyCreate
1561 //                    TSCacheKeyDigestSet
1562 //                    TSVConnCacheObjectSizeGet
1563 //                    TSVConnClose
1564 //                    TSVConnClosedGet
1565 //                    TSVConnRead
1566 //                    TSVConnReadVIOGet
1567 //                    TSVConnWrite
1568 //                    TSVConnWriteVIOGet
1569 //                    TSVIOBufferGet
1570 //                    TSVIOContGet
1571 //                    TSVIOMutexGet
1572 //                    TSVIONBytesGet
1573 //                    TSVIONBytesSet
1574 //                    TSVIONDoneGet
1575 //                    TSVIONDoneSet
1576 //                    TSVIONTodoGet
1577 //                    TSVIOReaderGet
1578 //                    TSVIOReenable
1579 //                    TSVIOVConnGet
1580 //////////////////////////////////////////////
1581 
1582 // TSVConnAbort can't be tested
1583 // Fix me: test TSVConnShutdown, TSCacheKeyDataTypeSet,
1584 //         TSCacheKeyHostNameSet, TSCacheKeyPinnedSet
1585 
1586 // Logic of the test:
1587 //  - write OBJECT_SIZE bytes in the cache in 3 shots
1588 //    (OBJECT_SIZE/2, then OBJECT_SIZE-100 and finally OBJECT_SIZE)
1589 //  - read object from the cache
1590 //  - remove it from the cache
1591 //  - try to read it (should fail)
1592 
1593 #define OBJECT_SIZE 100000 // size of the object we'll write/read/remove in cache
1594 
1595 RegressionTest *SDK_Cache_test;
1596 int *SDK_Cache_pstatus;
1597 static char content[OBJECT_SIZE];
1598 static int read_counter = 0;
1599 
1600 struct CacheVConnStruct {
1601   TSIOBuffer bufp;
1602   TSIOBuffer out_bufp;
1603   TSIOBufferReader readerp;
1604   TSIOBufferReader out_readerp;
1605 
1606   TSVConn write_vconnp;
1607   TSVConn read_vconnp;
1608   TSVIO read_vio;
1609   TSVIO write_vio;
1610 
1611   TSCacheKey key;
1612 };
1613 
1614 int
cache_handler(TSCont contp,TSEvent event,void * data)1615 cache_handler(TSCont contp, TSEvent event, void *data)
1616 {
1617   Debug("sdk_ut_cache_write", "Event %d data %p", event, data);
1618 
1619   CacheVConnStruct *cache_vconn = static_cast<CacheVConnStruct *>(TSContDataGet(contp));
1620 
1621   TSIOBufferBlock blockp;
1622   char *ptr_block;
1623   int64_t ntodo, ndone, nbytes, towrite, avail, content_length;
1624 
1625   switch (event) {
1626   case TS_EVENT_CACHE_OPEN_WRITE:
1627     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_WRITE %d %p", event, data);
1628     SDK_RPRINT(SDK_Cache_test, "TSCacheWrite", "TestCase1", TC_PASS, "ok");
1629 
1630     // data is write_vc
1631     cache_vconn->write_vconnp = static_cast<TSVConn>(data);
1632 
1633     // Create buffers/readers to write and read data into the cache
1634     cache_vconn->bufp        = TSIOBufferCreate();
1635     cache_vconn->readerp     = TSIOBufferReaderAlloc(cache_vconn->bufp);
1636     cache_vconn->out_bufp    = TSIOBufferCreate();
1637     cache_vconn->out_readerp = TSIOBufferReaderAlloc(cache_vconn->out_bufp);
1638 
1639     // Write content into upstream IOBuffer
1640     ntodo = OBJECT_SIZE;
1641     ndone = 0;
1642     while (ntodo > 0) {
1643       blockp    = TSIOBufferStart(cache_vconn->bufp);
1644       ptr_block = TSIOBufferBlockWriteStart(blockp, &avail);
1645       towrite   = ((ntodo < avail) ? ntodo : avail);
1646       memcpy(ptr_block, content + ndone, towrite);
1647       TSIOBufferProduce(cache_vconn->bufp, towrite);
1648       ntodo -= towrite;
1649       ndone += towrite;
1650     }
1651 
1652     // first write half of the data. To test TSVIOReenable
1653     cache_vconn->write_vio = TSVConnWrite(static_cast<TSVConn>(data), contp, cache_vconn->readerp, OBJECT_SIZE / 2);
1654     return 1;
1655 
1656   case TS_EVENT_CACHE_OPEN_WRITE_FAILED:
1657     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_WRITE_FAILED %d %p", event, data);
1658     SDK_RPRINT(SDK_Cache_test, "TSCacheWrite", "TestCase1", TC_FAIL, "can't open cache vc, edtata = %p", data);
1659     TSReleaseAssert(!"cache");
1660 
1661     // no need to continue, return
1662     *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1663     return 1;
1664 
1665   case TS_EVENT_CACHE_OPEN_READ:
1666     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_READ %d %p", event, data);
1667     if (read_counter == 2) {
1668       SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase2", TC_FAIL, "shouldn't open cache vc");
1669 
1670       // no need to continue, return
1671       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1672       return 1;
1673     }
1674 
1675     SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase1", TC_PASS, "ok");
1676 
1677     cache_vconn->read_vconnp = static_cast<TSVConn>(data);
1678     content_length           = TSVConnCacheObjectSizeGet(cache_vconn->read_vconnp);
1679     Debug(UTDBG_TAG "_cache_read", "In cache open read [Content-Length: %" PRId64 "]", content_length);
1680     if (content_length != OBJECT_SIZE) {
1681       SDK_RPRINT(SDK_Cache_test, "TSVConnCacheObjectSizeGet", "TestCase1", TC_FAIL, "cached data size is incorrect");
1682 
1683       // no need to continue, return
1684       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1685       return 1;
1686     } else {
1687       SDK_RPRINT(SDK_Cache_test, "TSVConnCacheObjectSizeGet", "TestCase1", TC_PASS, "ok");
1688       cache_vconn->read_vio = TSVConnRead(static_cast<TSVConn>(data), contp, cache_vconn->out_bufp, content_length);
1689     }
1690     return 1;
1691 
1692   case TS_EVENT_CACHE_OPEN_READ_FAILED:
1693     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_READ_FAILED %d %p", event, data);
1694     if (read_counter == 1) {
1695       SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase1", TC_FAIL, "can't open cache vc");
1696 
1697       // no need to continue, return
1698       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1699       return 1;
1700     }
1701     SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase2", TC_PASS, "ok");
1702 
1703     // ok, all tests passed!
1704     break;
1705 
1706   case TS_EVENT_CACHE_REMOVE:
1707     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_REMOVE %d %p", event, data);
1708     SDK_RPRINT(SDK_Cache_test, "TSCacheRemove", "TestCase1", TC_PASS, "ok");
1709 
1710     // read the data which has been removed
1711     read_counter++;
1712     TSCacheRead(contp, cache_vconn->key);
1713     return 1;
1714 
1715   case TS_EVENT_CACHE_REMOVE_FAILED:
1716     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_REMOVE_FAILED %d %p", event, data);
1717     SDK_RPRINT(SDK_Cache_test, "TSCacheRemove", "TestCase1", TC_FAIL, "can't remove cached item");
1718 
1719     // no need to continue, return
1720     *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1721     return 1;
1722 
1723   case TS_EVENT_VCONN_WRITE_COMPLETE:
1724     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_WRITE_COMPLETE %d %p", event, data);
1725 
1726     // VConn/VIO APIs
1727     nbytes = TSVIONBytesGet(cache_vconn->write_vio);
1728     ndone  = TSVIONDoneGet(cache_vconn->write_vio);
1729     ntodo  = TSVIONTodoGet(cache_vconn->write_vio);
1730     Debug(UTDBG_TAG "_cache_write", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1731 
1732     if (ndone == (OBJECT_SIZE / 2)) {
1733       TSVIONBytesSet(cache_vconn->write_vio, (OBJECT_SIZE - 100));
1734       TSVIOReenable(cache_vconn->write_vio);
1735       Debug(UTDBG_TAG "_cache_write", "Increment write_counter in write_complete [a]");
1736       return 1;
1737     } else if (ndone == (OBJECT_SIZE - 100)) {
1738       TSVIONBytesSet(cache_vconn->write_vio, OBJECT_SIZE);
1739       TSVIOReenable(cache_vconn->write_vio);
1740       Debug(UTDBG_TAG "_cache_write", "Increment write_counter in write_complete [b]");
1741       return 1;
1742     } else if (ndone == OBJECT_SIZE) {
1743       Debug(UTDBG_TAG "_cache_write", "finishing up [c]");
1744 
1745       SDK_RPRINT(SDK_Cache_test, "TSVIOReenable", "TestCase2", TC_PASS, "ok");
1746       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesSet", "TestCase1", TC_PASS, "ok");
1747       SDK_RPRINT(SDK_Cache_test, "TSVConnWrite", "TestCase1", TC_PASS, "ok");
1748     } else {
1749       SDK_RPRINT(SDK_Cache_test, "TSCacheWrite", "TestCase1", TC_FAIL, "Did not write expected # of bytes");
1750       // no need to continue, return
1751       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1752       return 1;
1753     }
1754 
1755     if (static_cast<TSVIO>(data) != cache_vconn->write_vio) {
1756       SDK_RPRINT(SDK_Cache_test, "TSVConnWrite", "TestCase1", TC_FAIL, "write_vio corrupted");
1757       // no need to continue, return
1758       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1759       return 1;
1760     }
1761     Debug(UTDBG_TAG "_cache_write", "finishing up [d]");
1762 
1763     if (TSVIOBufferGet(cache_vconn->write_vio) != cache_vconn->bufp) {
1764       SDK_RPRINT(SDK_Cache_test, "TSVIOBufferGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1765       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1766       return 1;
1767     } else {
1768       SDK_RPRINT(SDK_Cache_test, "TSVIOBufferGet", "TestCase1", TC_PASS, "ok");
1769     }
1770 
1771     if (TSVIOContGet(cache_vconn->write_vio) != contp) {
1772       SDK_RPRINT(SDK_Cache_test, "TSVIOContGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1773       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1774       return 1;
1775     } else {
1776       SDK_RPRINT(SDK_Cache_test, "TSVIOContGet", "TestCase1", TC_PASS, "ok");
1777     }
1778 
1779     Debug(UTDBG_TAG "_cache_write", "finishing up [f]");
1780 
1781     if (TSVIOMutexGet(cache_vconn->write_vio) != TSContMutexGet(contp)) {
1782       SDK_RPRINT(SDK_Cache_test, "TSVIOMutexGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1783       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1784       return 1;
1785     } else {
1786       SDK_RPRINT(SDK_Cache_test, "TSVIOMutexGet", "TestCase1", TC_PASS, "ok");
1787     }
1788 
1789     if (TSVIOVConnGet(cache_vconn->write_vio) != cache_vconn->write_vconnp) {
1790       SDK_RPRINT(SDK_Cache_test, "TSVIOVConnGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1791       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1792       return 1;
1793     } else {
1794       SDK_RPRINT(SDK_Cache_test, "TSVIOVConnGet", "TestCase1", TC_PASS, "ok");
1795     }
1796 
1797     Debug(UTDBG_TAG "_cache_write", "finishing up [g]");
1798 
1799     if (TSVIOReaderGet(cache_vconn->write_vio) != cache_vconn->readerp) {
1800       SDK_RPRINT(SDK_Cache_test, "TSVIOReaderGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1801       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1802       return 1;
1803     } else {
1804       SDK_RPRINT(SDK_Cache_test, "TSVIOReaderGet", "TestCase1", TC_PASS, "ok");
1805     }
1806 
1807     // tests for write is done, close write_vconnp
1808     TSVConnClose(cache_vconn->write_vconnp);
1809     cache_vconn->write_vconnp = nullptr;
1810 
1811     Debug(UTDBG_TAG "_cache_write", "finishing up [h]");
1812 
1813     // start to read data out of cache
1814     read_counter++;
1815     TSCacheRead(contp, cache_vconn->key);
1816     Debug(UTDBG_TAG "_cache_read", "starting read [i]");
1817     return 1;
1818 
1819   case TS_EVENT_VCONN_WRITE_READY:
1820     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_WRITE_READY %d %p", event, data);
1821     if (static_cast<TSVIO>(data) != cache_vconn->write_vio) {
1822       SDK_RPRINT(SDK_Cache_test, "TSVConnWrite", "TestCase1", TC_FAIL, "write_vio corrupted");
1823       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1824       return 1;
1825     }
1826 
1827     nbytes = TSVIONBytesGet(cache_vconn->write_vio);
1828     ndone  = TSVIONDoneGet(cache_vconn->write_vio);
1829     ntodo  = TSVIONTodoGet(cache_vconn->write_vio);
1830     Debug(UTDBG_TAG "_cache_write", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1831 
1832     TSVIOReenable(cache_vconn->write_vio);
1833     return 1;
1834 
1835   case TS_EVENT_VCONN_READ_COMPLETE:
1836     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_READ_COMPLETE %d %p", event, data);
1837     if (static_cast<TSVIO>(data) != cache_vconn->read_vio) {
1838       SDK_RPRINT(SDK_Cache_test, "TSVConnRead", "TestCase1", TC_FAIL, "read_vio corrupted");
1839 
1840       // no need to continue, return
1841       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1842       return 1;
1843     }
1844 
1845     nbytes = TSVIONBytesGet(cache_vconn->read_vio);
1846     ntodo  = TSVIONTodoGet(cache_vconn->read_vio);
1847     ndone  = TSVIONDoneGet(cache_vconn->read_vio);
1848     Debug(UTDBG_TAG "_cache_read", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1849 
1850     if (nbytes != (ndone + ntodo)) {
1851       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1852       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1853       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1854 
1855       // no need to continue, return
1856       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1857       return 1;
1858     } else {
1859       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_PASS, "ok");
1860       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_PASS, "ok");
1861       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_PASS, "ok");
1862 
1863       TSVIONDoneSet(cache_vconn->read_vio, 0);
1864       if (TSVIONDoneGet(cache_vconn->read_vio) != 0) {
1865         SDK_RPRINT(SDK_Cache_test, "TSVIONDoneSet", "TestCase1", TC_FAIL, "fail to set");
1866 
1867         // no need to continue, return
1868         *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1869         return 1;
1870       } else {
1871         SDK_RPRINT(SDK_Cache_test, "TSVIONDoneSet", "TestCase1", TC_PASS, "ok");
1872       }
1873 
1874       Debug(UTDBG_TAG "_cache_write", "finishing up [i]");
1875 
1876       // now waiting for 100ms to make sure the key is
1877       // written in directory remove the content
1878       TSContScheduleOnPool(contp, 100, TS_THREAD_POOL_NET);
1879     }
1880 
1881     return 1;
1882 
1883   case TS_EVENT_VCONN_READ_READY:
1884     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_READ_READY %d %p", event, data);
1885     if (static_cast<TSVIO>(data) != cache_vconn->read_vio) {
1886       SDK_RPRINT(SDK_Cache_test, "TSVConnRead", "TestCase1", TC_FAIL, "read_vio corrupted");
1887 
1888       // no need to continue, return
1889       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1890       return 1;
1891     }
1892 
1893     nbytes = TSVIONBytesGet(cache_vconn->read_vio);
1894     ntodo  = TSVIONTodoGet(cache_vconn->read_vio);
1895     ndone  = TSVIONDoneGet(cache_vconn->read_vio);
1896     Debug(UTDBG_TAG "_cache_read", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1897 
1898     if (nbytes != (ndone + ntodo)) {
1899       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1900       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1901       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1902 
1903       // no need to continue, return
1904       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1905       return 1;
1906     } else {
1907       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_PASS, "ok");
1908       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_PASS, "ok");
1909       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_PASS, "ok");
1910     }
1911 
1912     // Fix for bug INKqa12276: Must consume data from iobuffer
1913     nbytes = TSIOBufferReaderAvail(cache_vconn->out_readerp);
1914     TSIOBufferReaderConsume(cache_vconn->out_readerp, nbytes);
1915     TSDebug(UTDBG_TAG "_cache_read", "Consuming %" PRId64 " bytes from cache read VC", nbytes);
1916 
1917     TSVIOReenable(cache_vconn->read_vio);
1918     Debug(UTDBG_TAG "_cache_read", "finishing up [j]");
1919     return 1;
1920 
1921   case TS_EVENT_TIMEOUT:
1922     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_TIMEOUT %d %p", event, data);
1923     // do remove cached doc
1924     TSCacheRemove(contp, cache_vconn->key);
1925     return 1;
1926 
1927   default:
1928     TSReleaseAssert(!"Test SDK_API_TSCache: unexpected event");
1929   }
1930 
1931   Debug(UTDBG_TAG "_cache_event", "DONE DONE DONE");
1932 
1933   // destroy the data structure
1934   Debug(UTDBG_TAG "_cache_write", "all tests passed [z]");
1935   TSIOBufferDestroy(cache_vconn->bufp);
1936   TSIOBufferDestroy(cache_vconn->out_bufp);
1937   TSCacheKeyDestroy(cache_vconn->key);
1938   TSfree(cache_vconn);
1939   *SDK_Cache_pstatus = REGRESSION_TEST_PASSED;
1940 
1941   return 1;
1942 }
1943 
REGRESSION_TEST(SDK_API_TSCache)1944 REGRESSION_TEST(SDK_API_TSCache)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1945 {
1946   *pstatus          = REGRESSION_TEST_INPROGRESS;
1947   SDK_Cache_test    = test;
1948   SDK_Cache_pstatus = pstatus;
1949   int is_ready      = 0;
1950 
1951   // Check if Cache is ready
1952   TSCacheReady(&is_ready);
1953   if (!is_ready) {
1954     SDK_RPRINT(test, "TSCacheReady", "TestCase1", TC_FAIL, "cache is not ready");
1955 
1956     // no need to continue, return
1957     *pstatus = REGRESSION_TEST_FAILED;
1958     return;
1959   } else {
1960     SDK_RPRINT(test, "TSCacheReady", "TestCase1", TC_PASS, "ok");
1961   }
1962 
1963   // Create CacheKey
1964   char key_name[]    = "key_for_regression_test";
1965   TSCacheKey key     = TSCacheKeyCreate();
1966   TSCacheKey key_cmp = TSCacheKeyCreate();
1967   SDK_RPRINT(test, "TSCacheKeyCreate", "TestCase1", TC_PASS, "ok");
1968   TSCacheKeyDigestSet(key, key_name, strlen(key_name));
1969   TSCacheKeyDigestSet(key_cmp, key_name, strlen(key_name));
1970 
1971   // prepare caching content
1972   // string, null-terminated.
1973   for (int i = 0; i < (OBJECT_SIZE - 1); i++) {
1974     content[i] = 'a';
1975   }
1976   content[OBJECT_SIZE - 1] = '\0';
1977 
1978   // Write data to cache.
1979   TSCont contp                  = TSContCreate(cache_handler, TSMutexCreate());
1980   CacheVConnStruct *cache_vconn = static_cast<CacheVConnStruct *>(TSmalloc(sizeof(CacheVConnStruct)));
1981   cache_vconn->key              = key;
1982   TSContDataSet(contp, cache_vconn);
1983 
1984   TSCacheWrite(contp, key);
1985 }
1986 
1987 /* TSfopen */
1988 
1989 //////////////////////////////////////////////
1990 //       SDK_API_TSfopen
1991 //
1992 // Unit Test for API: TSfopen
1993 //                    TSclose
1994 //                    TSfflush
1995 //                    TSfgets
1996 //                    TSfread
1997 //                    TSfwrite
1998 //////////////////////////////////////////////
1999 
2000 // Note that for each test, if it fails, we set the error status and return.
REGRESSION_TEST(SDK_API_TSfopen)2001 REGRESSION_TEST(SDK_API_TSfopen)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2002 {
2003   *pstatus = REGRESSION_TEST_INPROGRESS;
2004 
2005   char write_file_name[PATH_NAME_MAX];
2006 
2007   TSFile source_read_file; // existing file
2008   TSFile write_file;       // to be created
2009   TSFile cmp_read_file;    // read & compare
2010 
2011   char input_buffer[BUFSIZ];
2012   char cmp_buffer[BUFSIZ];
2013   struct stat stat_buffer_pre, stat_buffer_post, stat_buffer_input;
2014   char *ret_val;
2015   int read = 0, wrote = 0;
2016   int64_t read_amount = 0;
2017   char input_file_full_path[BUFSIZ];
2018 
2019   // Set full path to file at run time.
2020   // TODO: This can never fail since we are
2021   //       returning the char[]
2022   //       Better check the dir itself.
2023   //
2024   if (TSInstallDirGet() == nullptr) {
2025     *pstatus = REGRESSION_TEST_FAILED;
2026     return;
2027   }
2028   // Add "etc/trafficserver" to point to config directory
2029   ink_filepath_make(input_file_full_path, sizeof(input_file_full_path), TSConfigDirGet(), ts::filename::PLUGIN);
2030 
2031   // open existing file for reading
2032   if (!(source_read_file = TSfopen(input_file_full_path, "r"))) {
2033     SDK_RPRINT(test, "TSfopen", "TestCase1", TC_FAIL, "can't open file for reading");
2034 
2035     // no need to continue, return
2036     *pstatus = REGRESSION_TEST_FAILED;
2037     return;
2038   } else {
2039     SDK_RPRINT(test, "TSfopen", "TestCase1", TC_PASS, "ok");
2040   }
2041 
2042   // Create unique tmp _file_name_, do not use any TS file_name
2043   snprintf(write_file_name, PATH_NAME_MAX, "/tmp/%sXXXXXX", ts::filename::PLUGIN);
2044   int write_file_fd; // this file will be reopened below
2045   if ((write_file_fd = mkstemp(write_file_name)) <= 0) {
2046     SDK_RPRINT(test, "mkstemp", "std func", TC_FAIL, "can't create file for writing");
2047 
2048     // no need to continue, return
2049     *pstatus = REGRESSION_TEST_FAILED;
2050     if (source_read_file != nullptr) {
2051       TSfclose(source_read_file);
2052     }
2053     return;
2054   }
2055   close(write_file_fd);
2056 
2057   // open file for writing, the file doesn't have to exist.
2058   if (!(write_file = TSfopen(write_file_name, "w"))) {
2059     SDK_RPRINT(test, "TSfopen", "TestCase2", TC_FAIL, "can't open file for writing");
2060 
2061     // no need to continue, return
2062     *pstatus = REGRESSION_TEST_FAILED;
2063     if (source_read_file != nullptr) {
2064       TSfclose(source_read_file);
2065     }
2066     return;
2067   }
2068   SDK_RPRINT(test, "TSfopen", "TestCase2", TC_PASS, "ok");
2069 
2070   memset(input_buffer, '\0', BUFSIZ);
2071 
2072   // source_read_file and input_file_full_path are the same file
2073   if (stat(input_file_full_path, &stat_buffer_input) != 0) {
2074     SDK_RPRINT(test, "stat", "std func", TC_FAIL, "source file and input file messed up");
2075 
2076     // no need to continue, return
2077     *pstatus = REGRESSION_TEST_FAILED;
2078     if (source_read_file != nullptr) {
2079       TSfclose(source_read_file);
2080     }
2081     if (write_file != nullptr) {
2082       TSfclose(write_file);
2083     }
2084     return;
2085   }
2086 
2087   read_amount =
2088     (stat_buffer_input.st_size <= static_cast<off_t>(sizeof(input_buffer))) ? (stat_buffer_input.st_size) : (sizeof(input_buffer));
2089 
2090   // TSfgets
2091   if ((ret_val = TSfgets(source_read_file, input_buffer, read_amount)) == nullptr) {
2092     SDK_RPRINT(test, "TSfgets", "TestCase1", TC_FAIL, "can't read from file");
2093 
2094     // no need to continue, return
2095     *pstatus = REGRESSION_TEST_FAILED;
2096     if (source_read_file != nullptr) {
2097       TSfclose(source_read_file);
2098     }
2099     if (write_file != nullptr) {
2100       TSfclose(write_file);
2101     }
2102     return;
2103   } else {
2104     if (ret_val != input_buffer) {
2105       SDK_RPRINT(test, "TSfgets", "TestCase2", TC_FAIL, "reading error");
2106 
2107       // no need to continue, return
2108       *pstatus = REGRESSION_TEST_FAILED;
2109       if (source_read_file != nullptr) {
2110         TSfclose(source_read_file);
2111       }
2112       if (write_file != nullptr) {
2113         TSfclose(write_file);
2114       }
2115       return;
2116     } else {
2117       SDK_RPRINT(test, "TSfgets", "TestCase1", TC_PASS, "ok");
2118     }
2119   }
2120 
2121   // TSfwrite
2122   wrote = TSfwrite(write_file, input_buffer, read_amount);
2123   if (wrote != read_amount) {
2124     SDK_RPRINT(test, "TSfwrite", "TestCase1", TC_FAIL, "writing error");
2125 
2126     // no need to continue, return
2127     *pstatus = REGRESSION_TEST_FAILED;
2128     if (source_read_file != nullptr) {
2129       TSfclose(source_read_file);
2130     }
2131     if (write_file != nullptr) {
2132       TSfclose(write_file);
2133     }
2134     return;
2135   }
2136 
2137   SDK_RPRINT(test, "TSfwrite", "TestCase1", TC_PASS, "ok");
2138 
2139   // TSfflush
2140   if (stat(write_file_name, &stat_buffer_pre) != 0) {
2141     SDK_RPRINT(test, "stat", "std func", TC_FAIL, "TSfwrite error");
2142 
2143     // no need to continue, return
2144     *pstatus = REGRESSION_TEST_FAILED;
2145     if (source_read_file != nullptr) {
2146       TSfclose(source_read_file);
2147     }
2148     if (write_file != nullptr) {
2149       TSfclose(write_file);
2150     }
2151     return;
2152   }
2153 
2154   TSfflush(write_file); // write_file should point to write_file_name
2155 
2156   if (stat(write_file_name, &stat_buffer_post) != 0) {
2157     SDK_RPRINT(test, "stat", "std func", TC_FAIL, "TSfflush error");
2158 
2159     // no need to continue, return
2160     *pstatus = REGRESSION_TEST_FAILED;
2161     if (source_read_file != nullptr) {
2162       TSfclose(source_read_file);
2163     }
2164     if (write_file != nullptr) {
2165       TSfclose(write_file);
2166     }
2167     return;
2168   }
2169 
2170   if ((stat_buffer_pre.st_size == 0) && (stat_buffer_post.st_size == read_amount)) {
2171     SDK_RPRINT(test, "TSfflush", "TestCase1", TC_PASS, "ok");
2172   } else {
2173     SDK_RPRINT(test, "TSfflush", "TestCase1", TC_FAIL, "TSfflush error");
2174 
2175     // no need to continue, return
2176     *pstatus = REGRESSION_TEST_FAILED;
2177     if (source_read_file != nullptr) {
2178       TSfclose(source_read_file);
2179     }
2180     if (write_file != nullptr) {
2181       TSfclose(write_file);
2182     }
2183     return;
2184   }
2185 
2186   // TSfread
2187   // open again for reading
2188   cmp_read_file = TSfopen(write_file_name, "r");
2189   if (cmp_read_file == nullptr) {
2190     SDK_RPRINT(test, "TSfopen", "TestCase3", TC_FAIL, "can't open file for reading");
2191 
2192     // no need to continue, return
2193     *pstatus = REGRESSION_TEST_FAILED;
2194     if (source_read_file != nullptr) {
2195       TSfclose(source_read_file);
2196     }
2197     if (write_file != nullptr) {
2198       TSfclose(write_file);
2199     }
2200     return;
2201   }
2202 
2203   read_amount =
2204     (stat_buffer_input.st_size <= static_cast<off_t>(sizeof(cmp_buffer))) ? (stat_buffer_input.st_size) : (sizeof(cmp_buffer));
2205 
2206   // TSfread on read file
2207   read = TSfread(cmp_read_file, cmp_buffer, read_amount);
2208   if (read != read_amount) {
2209     SDK_RPRINT(test, "TSfread", "TestCase1", TC_FAIL, "can't reading");
2210 
2211     // no need to continue, return
2212     *pstatus = REGRESSION_TEST_FAILED;
2213     if (source_read_file != nullptr) {
2214       TSfclose(source_read_file);
2215     }
2216     if (write_file != nullptr) {
2217       TSfclose(write_file);
2218     }
2219     if (cmp_read_file != nullptr) {
2220       TSfclose(cmp_read_file);
2221     }
2222     return;
2223   } else {
2224     SDK_RPRINT(test, "TSfread", "TestCase1", TC_PASS, "ok");
2225   }
2226 
2227   // compare input_buffer and cmp_buffer buffers
2228   if (memcmp(input_buffer, cmp_buffer, read_amount) != 0) {
2229     SDK_RPRINT(test, "TSfread", "TestCase2", TC_FAIL, "reading error");
2230 
2231     // no need to continue, return
2232     *pstatus = REGRESSION_TEST_FAILED;
2233     if (source_read_file != nullptr) {
2234       TSfclose(source_read_file);
2235     }
2236     if (write_file != nullptr) {
2237       TSfclose(write_file);
2238     }
2239     if (cmp_read_file != nullptr) {
2240       TSfclose(cmp_read_file);
2241     }
2242     return;
2243   } else {
2244     SDK_RPRINT(test, "TSfread", "TestCase2", TC_PASS, "ok");
2245   }
2246 
2247   // remove the tmp file
2248   if (unlink(write_file_name) != 0) {
2249     SDK_RPRINT(test, "unlink", "std func", TC_FAIL, "can't remove temp file");
2250   }
2251   // TSfclose on read file
2252   TSfclose(source_read_file);
2253   SDK_RPRINT(test, "TSfclose", "TestCase1", TC_PASS, "ok");
2254 
2255   // TSfclose on write file
2256   TSfclose(write_file);
2257   SDK_RPRINT(test, "TSfclose", "TestCase2", TC_PASS, "ok");
2258 
2259   *pstatus = REGRESSION_TEST_PASSED;
2260   if (cmp_read_file != nullptr) {
2261     TSfclose(cmp_read_file);
2262   }
2263 }
2264 
2265 /* TSThread */
2266 
2267 //////////////////////////////////////////////
2268 //       SDK_API_TSThread
2269 //
2270 // Unit Test for API: TSThread
2271 //                    TSThreadCreate
2272 //                    TSThreadSelf
2273 //////////////////////////////////////////////
2274 static int thread_err_count = 0;
2275 static RegressionTest *SDK_Thread_test;
2276 static int *SDK_Thread_pstatus;
2277 static void *thread_create_handler(void *arg);
2278 
2279 static void *
thread_create_handler(void *)2280 thread_create_handler(void * /* arg ATS_UNUSED */)
2281 {
2282   TSThread athread;
2283   // Fix me: do more useful work
2284   sleep(10);
2285 
2286   athread = TSThreadSelf();
2287   if (athread == nullptr) {
2288     thread_err_count++;
2289     SDK_RPRINT(SDK_Thread_test, "TSThreadCreate", "TestCase2", TC_FAIL, "can't get thread");
2290   } else {
2291     SDK_RPRINT(SDK_Thread_test, "TSThreadCreate", "TestCase2", TC_PASS, "ok");
2292   }
2293 
2294   if (thread_err_count > 0) {
2295     *SDK_Thread_pstatus = REGRESSION_TEST_FAILED;
2296   } else {
2297     *SDK_Thread_pstatus = REGRESSION_TEST_PASSED;
2298   }
2299 
2300   return nullptr;
2301 }
2302 
2303 // Fix me: Solaris threads/Win2K threads tests
2304 
2305 // Argument data passed to thread init functions
2306 //  cannot be allocated on the stack.
2307 
REGRESSION_TEST(SDK_API_TSThread)2308 REGRESSION_TEST(SDK_API_TSThread)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2309 {
2310   *pstatus           = REGRESSION_TEST_INPROGRESS;
2311   SDK_Thread_test    = test;
2312   SDK_Thread_pstatus = pstatus;
2313 
2314   TSThread curr_thread = nullptr;
2315   //    TSThread created_thread = 0;
2316   pthread_t curr_tid;
2317 
2318   curr_tid = pthread_self();
2319 
2320   // TSThreadSelf
2321   curr_thread = TSThreadSelf();
2322   if (curr_thread == nullptr) {
2323     SDK_RPRINT(test, "TSThreadSelf", "TestCase1", TC_FAIL, "can't get the current thread");
2324     thread_err_count++;
2325   } else {
2326     SDK_RPRINT(test, "TSThreadSelf", "TestCase1", TC_PASS, "ok");
2327   }
2328 
2329   // TSThreadCreate
2330   TSThread created_thread = TSThreadCreate(thread_create_handler, reinterpret_cast<void *>(curr_tid));
2331   if (created_thread == nullptr) {
2332     thread_err_count++;
2333     SDK_RPRINT(test, "TSThreadCreate", "TestCase1", TC_FAIL, "can't create thread");
2334   } else {
2335     SDK_RPRINT(test, "TSThreadCreate", "TestCase1", TC_PASS, "ok");
2336   }
2337 
2338   if (created_thread != nullptr) {
2339     TSThreadWait(created_thread);
2340     TSThreadDestroy(created_thread);
2341   }
2342 }
2343 
2344 //////////////////////////////////////////////
2345 //       SDK_API_TSThread
2346 //
2347 // Unit Test for API: TSThreadInit
2348 //                    TSThreadDestroy
2349 //////////////////////////////////////////////
2350 static int thread_init_err_count = 0;
2351 static RegressionTest *SDK_ThreadInit_test;
2352 static int *SDK_ThreadInit_pstatus;
2353 static void *pthread_start_func(void *arg);
2354 
2355 static void *
pthread_start_func(void *)2356 pthread_start_func(void * /* arg ATS_UNUSED */)
2357 {
2358   TSThread temp_thread = nullptr;
2359 
2360   // TSThreadInit
2361   temp_thread = TSThreadInit();
2362 
2363   if (!temp_thread) {
2364     SDK_RPRINT(SDK_ThreadInit_test, "TSThreadInit", "TestCase2", TC_FAIL, "can't init thread");
2365     thread_init_err_count++;
2366   } else {
2367     SDK_RPRINT(SDK_ThreadInit_test, "TSThreadInit", "TestCase2", TC_PASS, "ok");
2368   }
2369 
2370   // Clean up this thread
2371   if (temp_thread) {
2372     TSThreadDestroy(temp_thread);
2373   }
2374 
2375   if (thread_init_err_count > 0) {
2376     *SDK_ThreadInit_pstatus = REGRESSION_TEST_FAILED;
2377   } else {
2378     *SDK_ThreadInit_pstatus = REGRESSION_TEST_PASSED;
2379   }
2380 
2381   return nullptr;
2382 }
2383 
REGRESSION_TEST(SDK_API_TSThreadInit)2384 REGRESSION_TEST(SDK_API_TSThreadInit)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2385 {
2386   *pstatus               = REGRESSION_TEST_INPROGRESS;
2387   SDK_ThreadInit_test    = test;
2388   SDK_ThreadInit_pstatus = pstatus;
2389 
2390   pthread_t curr_tid, new_tid;
2391 
2392   curr_tid = pthread_self();
2393 
2394   int ret;
2395   errno = 0;
2396   ret   = pthread_create(&new_tid, nullptr, pthread_start_func, reinterpret_cast<void *>(curr_tid));
2397   if (ret != 0) {
2398     thread_init_err_count++;
2399     SDK_RPRINT(test, "TSThreadInit", "TestCase1", TC_FAIL, "can't create pthread");
2400   } else {
2401     SDK_RPRINT(test, "TSThreadInit", "TestCase1", TC_PASS, "ok");
2402   }
2403 }
2404 
2405 /* Action */
2406 
2407 //////////////////////////////////////////////
2408 //       SDK_API_TSAction
2409 //
2410 // Unit Test for API: TSActionCancel
2411 //////////////////////////////////////////////
2412 
2413 static RegressionTest *SDK_ActionCancel_test;
2414 static int *SDK_ActionCancel_pstatus;
2415 
2416 int
action_cancel_handler(TSCont contp,TSEvent event,void *)2417 action_cancel_handler(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
2418 {
2419   if (event == TS_EVENT_IMMEDIATE) { // called from schedule_imm OK
2420     SDK_RPRINT(SDK_ActionCancel_test, "TSActionCancel", "TestCase1", TC_PASS, "ok");
2421     *SDK_ActionCancel_pstatus = REGRESSION_TEST_PASSED;
2422   } else if (event == TS_EVENT_TIMEOUT) { // called from schedule_in Not OK.
2423     SDK_RPRINT(SDK_ActionCancel_test, "TSActionCancel", "TestCase1", TC_FAIL, "bad action");
2424     *SDK_ActionCancel_pstatus = REGRESSION_TEST_FAILED;
2425   } else { // there is sth wrong
2426     SDK_RPRINT(SDK_ActionCancel_test, "TSActionCancel", "TestCase1", TC_FAIL, "bad event");
2427     *SDK_ActionCancel_pstatus = REGRESSION_TEST_FAILED;
2428   }
2429 
2430   TSContDestroy(contp);
2431   return 0;
2432 }
2433 
REGRESSION_TEST(SDK_API_TSActionCancel)2434 REGRESSION_TEST(SDK_API_TSActionCancel)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2435 {
2436   *pstatus = REGRESSION_TEST_INPROGRESS;
2437 
2438   SDK_ActionCancel_test    = test;
2439   SDK_ActionCancel_pstatus = pstatus;
2440 
2441   TSMutex cont_mutex = TSMutexCreate();
2442   TSCont contp       = TSContCreate(action_cancel_handler, cont_mutex);
2443   TSAction actionp   = TSContScheduleOnPool(contp, 10000, TS_THREAD_POOL_NET);
2444 
2445   TSMutexLock(cont_mutex);
2446   if (TSActionDone(actionp)) {
2447     *pstatus = REGRESSION_TEST_FAILED;
2448     TSMutexUnlock(cont_mutex);
2449     return;
2450   } else {
2451     TSActionCancel(actionp);
2452   }
2453   TSMutexUnlock(cont_mutex);
2454 
2455   TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
2456 }
2457 
2458 //////////////////////////////////////////////
2459 //       SDK_API_TSAction
2460 //
2461 // Unit Test for API: TSActionDone
2462 //////////////////////////////////////////////
2463 /* Currently, don't know how to test it because TSAction
2464    is at "done" status only "shortly" after finish
2465    executing action_done_handler. Another possibility is
2466    to use reentrant call. But in both cases it's not
2467    guaranteed to get ActionDone.
2468    */
2469 
2470 /* Continuations */
2471 
2472 //////////////////////////////////////////////
2473 //       SDK_API_TSCont
2474 //
2475 // Unit Test for API: TSContCreate
2476 //                    TSContCall
2477 //////////////////////////////////////////////
2478 
2479 // this is needed for asynchronous APIs
2480 static RegressionTest *SDK_ContCreate_test;
2481 static int *SDK_ContCreate_pstatus;
2482 
2483 int
cont_handler(TSCont,TSEvent,void *)2484 cont_handler(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
2485 {
2486   SDK_RPRINT(SDK_ContCreate_test, "TSContCreate", "TestCase1", TC_PASS, "ok");
2487   SDK_RPRINT(SDK_ContCreate_test, "TSContCall", "TestCase1", TC_PASS, "ok");
2488 
2489   *SDK_ContCreate_pstatus = REGRESSION_TEST_PASSED;
2490 
2491   return 0;
2492 }
2493 
REGRESSION_TEST(SDK_API_TSContCreate)2494 REGRESSION_TEST(SDK_API_TSContCreate)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2495 {
2496   *pstatus = REGRESSION_TEST_INPROGRESS;
2497 
2498   // For asynchronous APIs, use static vars to store test and pstatus
2499   SDK_ContCreate_test    = test;
2500   SDK_ContCreate_pstatus = pstatus;
2501 
2502   TSMutex mutexp = TSMutexCreate();
2503   TSCont contp   = TSContCreate(cont_handler, mutexp);
2504 
2505   if (TS_SUCCESS == TSMutexLockTry(mutexp)) { // Mutex is grabbed successfully
2506     TSContCall(contp, static_cast<TSEvent>(0), nullptr);
2507     TSMutexUnlock(mutexp);
2508   } else { // mutex has problems
2509     SDK_RPRINT(SDK_ContCreate_test, "TSContCreate", "TestCase1", TC_FAIL, "continuation creation has problems");
2510     SDK_RPRINT(SDK_ContCreate_test, "TSContCall", "TestCase1", TC_FAIL, "continuation has problems");
2511 
2512     *pstatus = REGRESSION_TEST_FAILED;
2513   }
2514 
2515   TSContDestroy(contp);
2516 }
2517 
2518 //////////////////////////////////////////////
2519 //       SDK_API_TSCont
2520 //
2521 // Unit Test for API: TSContDataGet
2522 //                    TSContDataSet
2523 //////////////////////////////////////////////
2524 
2525 // this is needed for asynchronous APIs
2526 static RegressionTest *SDK_ContData_test;
2527 static int *SDK_ContData_pstatus;
2528 
2529 // this is specific for this test
2530 struct MyData {
2531   int data1;
2532   int data2;
2533 };
2534 
2535 int
cont_data_handler(TSCont contp,TSEvent,void *)2536 cont_data_handler(TSCont contp, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
2537 {
2538   MyData *my_data = static_cast<MyData *>(TSContDataGet(contp));
2539 
2540   if (my_data->data1 == 1 && my_data->data2 == 2) {
2541     SDK_RPRINT(SDK_ContData_test, "TSContDataSet", "TestCase1", TC_PASS, "ok");
2542     SDK_RPRINT(SDK_ContData_test, "TSContDataGet", "TestCase1", TC_PASS, "ok");
2543 
2544     *SDK_ContData_pstatus = REGRESSION_TEST_PASSED;
2545   } else {
2546     // If we get bad data, it's a failure
2547     SDK_RPRINT(SDK_ContData_test, "TSContDataSet", "TestCase1", TC_FAIL, "bad data");
2548     SDK_RPRINT(SDK_ContData_test, "TSContDataGet", "TestCase1", TC_FAIL, "bad data");
2549 
2550     *SDK_ContData_pstatus = REGRESSION_TEST_FAILED;
2551   }
2552 
2553   TSfree(my_data);
2554   TSContDestroy(contp);
2555   return 0;
2556 }
2557 
REGRESSION_TEST(SDK_API_TSContDataGet)2558 REGRESSION_TEST(SDK_API_TSContDataGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2559 {
2560   *pstatus = REGRESSION_TEST_INPROGRESS;
2561 
2562   // For asynchronous APIs, use static vars to store test and pstatus
2563   SDK_ContData_test    = test;
2564   SDK_ContData_pstatus = pstatus;
2565 
2566   TSCont contp = TSContCreate(cont_data_handler, TSMutexCreate());
2567 
2568   MyData *my_data = static_cast<MyData *>(TSmalloc(sizeof(MyData)));
2569   my_data->data1  = 1;
2570   my_data->data2  = 2;
2571 
2572   TSContDataSet(contp, (void *)my_data);
2573 
2574   TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
2575 }
2576 
2577 //////////////////////////////////////////////
2578 //       SDK_API_TSCont
2579 //
2580 // Unit Test for API: TSContMutexGet
2581 //////////////////////////////////////////////
2582 
REGRESSION_TEST(SDK_API_TSContMutexGet)2583 REGRESSION_TEST(SDK_API_TSContMutexGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2584 {
2585   bool test_passed = false;
2586   *pstatus         = REGRESSION_TEST_INPROGRESS;
2587 
2588   TSMutex mutexp_input;
2589   TSMutex mutexp_output;
2590   TSCont contp;
2591 
2592   mutexp_input = TSMutexCreate();
2593   contp        = TSContCreate(cont_handler, mutexp_input);
2594 
2595   mutexp_output = TSContMutexGet(contp);
2596 
2597   if (mutexp_input == mutexp_output) {
2598     SDK_RPRINT(test, "TSContMutexGet", "TestCase1", TC_PASS, "ok");
2599     test_passed = true;
2600   } else {
2601     SDK_RPRINT(test, "TSContMutexGet", "TestCase1", TC_FAIL, "Continuation's mutex corrupted");
2602   }
2603 
2604   // Status of the whole test
2605   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2606 
2607   TSContDestroy(contp);
2608 }
2609 
2610 //////////////////////////////////////////////
2611 //       SDK_API_TSCont
2612 //
2613 // Unit Test for API: TSContScheduleOnPool
2614 //////////////////////////////////////////////
2615 
2616 // this is needed for asynchronous APIs
2617 static RegressionTest *SDK_ContSchedule_test;
2618 static int *SDK_ContSchedule_pstatus;
2619 
2620 // this is specific for this test
2621 static int tc1_count = 0;
2622 static int tc2_count = 0;
2623 
2624 int
cont_schedule_handler(TSCont contp,TSEvent event,void *)2625 cont_schedule_handler(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
2626 {
2627   if (event == TS_EVENT_IMMEDIATE) {
2628     // Test Case 1
2629     SDK_RPRINT(SDK_ContSchedule_test, "TSContScheduleOnPool", "TestCase1", TC_PASS, "ok");
2630     tc1_count++;
2631   } else if (event == TS_EVENT_TIMEOUT) {
2632     // Test Case 2
2633     SDK_RPRINT(SDK_ContSchedule_test, "TSContScheduleOnPool", "TestCase2", TC_PASS, "ok");
2634     tc2_count++;
2635   } else {
2636     // If we receive a bad event, it's a failure
2637     SDK_RPRINT(SDK_ContSchedule_test, "TSContScheduleOnPool", "TestCase1|2", TC_FAIL, "received unexpected event number %d", event);
2638     *SDK_ContSchedule_pstatus = REGRESSION_TEST_FAILED;
2639     return 0;
2640   }
2641 
2642   // We expect to be called once for TC1 and once for TC2
2643   if ((tc1_count == 1) && (tc2_count == 1)) {
2644     *SDK_ContSchedule_pstatus = REGRESSION_TEST_PASSED;
2645   }
2646   // If TC1 or TC2 executed more than once, something is fishy..
2647   else if (tc1_count + tc2_count >= 2) {
2648     *SDK_ContSchedule_pstatus = REGRESSION_TEST_FAILED;
2649   }
2650 
2651   TSContDestroy(contp);
2652   return 0;
2653 }
2654 
2655 /* Mutex */
2656 
2657 /*
2658    Fix me: test for grabbing the mutex from two
2659    different threads.
2660    */
2661 
2662 //////////////////////////////////////////////
2663 //       SDK_API_TSMutex
2664 //
2665 // Unit Test for API: TSMutexCreate
2666 //                    TSMutexLock
2667 //                    TSMutexUnLock
2668 //////////////////////////////////////////////
2669 
REGRESSION_TEST(SDK_API_TSMutexCreate)2670 REGRESSION_TEST(SDK_API_TSMutexCreate)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2671 {
2672   bool test_passed = false;
2673   *pstatus         = REGRESSION_TEST_INPROGRESS;
2674 
2675   TSMutex mutexp = TSMutexCreate();
2676 
2677   TSMutexLock(mutexp);
2678 
2679   /* This is normal because all locking is from the same thread */
2680   TSReturnCode lock1 = TS_ERROR;
2681   TSReturnCode lock2 = TS_ERROR;
2682 
2683   lock1 = TSMutexLockTry(mutexp);
2684   lock2 = TSMutexLockTry(mutexp);
2685 
2686   if (TS_SUCCESS == lock1 && TS_SUCCESS == lock2) {
2687     SDK_RPRINT(test, "TSMutexCreate", "TestCase1", TC_PASS, "ok");
2688     SDK_RPRINT(test, "TSMutexLock", "TestCase1", TC_PASS, "ok");
2689     SDK_RPRINT(test, "TSMutexLockTry", "TestCase1", TC_PASS, "ok");
2690     test_passed = true;
2691   } else {
2692     SDK_RPRINT(test, "TSMutexCreate", "TestCase1", TC_FAIL, "mutex can't be grabbed twice from the same thread");
2693     SDK_RPRINT(test, "TSMutexLock", "TestCase1", TC_FAIL, "mutex can't be grabbed twice from the same thread");
2694     SDK_RPRINT(test, "TSMutexLockTry", "TestCase1", TC_FAIL, "mutex can't be grabbed twice from the same thread");
2695   }
2696 
2697   TSMutexUnlock(mutexp);
2698   SDK_RPRINT(test, "TSMutexUnLock", "TestCase1", TC_PASS, "ok");
2699 
2700   if (test_passed) {
2701     *pstatus = REGRESSION_TEST_PASSED;
2702   } else {
2703     *pstatus = REGRESSION_TEST_FAILED;
2704   }
2705 }
2706 
2707 /* IOBuffer */
2708 
2709 //////////////////////////////////////////////
2710 //       SDK_API_TSIOBuffer
2711 //
2712 // Unit Test for API: TSIOBufferCreate
2713 //                    TSIOBufferWaterMarkGet
2714 //                    TSIOBufferWaterMarkSet
2715 //////////////////////////////////////////////
2716 
REGRESSION_TEST(SDK_API_TSIOBufferCreate)2717 REGRESSION_TEST(SDK_API_TSIOBufferCreate)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2718 {
2719   bool test_passed = false;
2720   *pstatus         = REGRESSION_TEST_INPROGRESS;
2721 
2722   int64_t watermark = 1000;
2723 
2724   TSIOBuffer bufp = TSIOBufferCreate();
2725 
2726   TSIOBufferWaterMarkSet(bufp, watermark);
2727   watermark = TSIOBufferWaterMarkGet(bufp);
2728 
2729   if (watermark == 1000) {
2730     SDK_RPRINT(test, "TSIOBufferCreate", "TestCase1", TC_PASS, "ok");
2731     SDK_RPRINT(test, "TSIOBufferWaterMarkGet", "TestCase1", TC_PASS, "ok");
2732     SDK_RPRINT(test, "TSIOBufferWaterMarkSet", "TestCase1", TC_PASS, "ok");
2733     test_passed = true;
2734   } else {
2735     SDK_RPRINT(test, "TSIOBufferCreate", "TestCase1", TC_FAIL, "watermark failed");
2736     SDK_RPRINT(test, "TSIOBufferWaterMarkGet", "TestCase1", TC_FAIL, "watermark failed");
2737     SDK_RPRINT(test, "TSIOBufferWaterMarkSet", "TestCase1", TC_FAIL, "watermark failed");
2738   }
2739 
2740   TSIOBufferDestroy(bufp);
2741 
2742   // Status of the whole test
2743   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2744   return;
2745 }
2746 
2747 //////////////////////////////////////////////
2748 //       SDK_API_TSIOBuffer
2749 //
2750 // Unit Test for API: TSIOBufferSizedCreate
2751 //                    TSIOBufferProduce
2752 //                    TSIOBufferReaderAlloc
2753 //                    TSIOBufferReaderAvail
2754 //////////////////////////////////////////////
2755 
REGRESSION_TEST(SDK_API_TSIOBufferProduce)2756 REGRESSION_TEST(SDK_API_TSIOBufferProduce)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2757 {
2758   bool test_passed = false;
2759   *pstatus         = REGRESSION_TEST_INPROGRESS;
2760 
2761   TSIOBuffer bufp = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K); // size is 4096
2762 
2763   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2764 
2765   TSIOBufferProduce(bufp, 10);
2766 
2767   int64_t reader_avail = TSIOBufferReaderAvail(readerp);
2768   if (reader_avail == 10) {
2769     SDK_RPRINT(test, "TSIOBufferProduce", "TestCase1", TC_PASS, "ok");
2770     SDK_RPRINT(test, "TSIOBufferReaderAlloc", "TestCase1", TC_PASS, "ok");
2771     SDK_RPRINT(test, "TSIOBufferReaderAvail", "TestCase1", TC_PASS, "ok");
2772     test_passed = true;
2773   } else {
2774     SDK_RPRINT(test, "TSIOBufferProduce", "TestCase1", TC_FAIL, "failed");
2775     SDK_RPRINT(test, "TSIOBufferReaderAlloc", "TestCase1", TC_FAIL, "failed");
2776     SDK_RPRINT(test, "TSIOBufferReaderAvail", "TestCase1", TC_FAIL, "failed");
2777   }
2778 
2779   // Status of the whole test
2780   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2781   return;
2782 }
2783 
2784 //////////////////////////////////////////////
2785 //       SDK_API_TSIOBuffer
2786 //
2787 // Unit Test for API: TSIOBufferReaderConsume
2788 //////////////////////////////////////////////
2789 
REGRESSION_TEST(SDK_API_TSIOBufferReaderConsume)2790 REGRESSION_TEST(SDK_API_TSIOBufferReaderConsume)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2791 {
2792   bool test_passed = false;
2793   *pstatus         = REGRESSION_TEST_INPROGRESS;
2794 
2795   TSIOBuffer bufp = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2796 
2797   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2798 
2799   TSIOBufferProduce(bufp, 10);
2800   TSIOBufferReaderConsume(readerp, 10);
2801 
2802   int64_t reader_avail = TSIOBufferReaderAvail(readerp);
2803   if (reader_avail == 0) {
2804     SDK_RPRINT(test, "TSIOBufferReaderConsume", "TestCase1", TC_PASS, "ok");
2805     test_passed = true;
2806   } else {
2807     SDK_RPRINT(test, "TSIOBufferReaderConsume", "TestCase1", TC_FAIL, "failed");
2808   }
2809 
2810   // Status of the whole test
2811   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2812   return;
2813 }
2814 
2815 //////////////////////////////////////////////
2816 //       SDK_API_TSIOBuffer
2817 //
2818 // Unit Test for API: TSIOBufferReaderClone
2819 //////////////////////////////////////////////
2820 
REGRESSION_TEST(SDK_API_TSIOBufferReaderClone)2821 REGRESSION_TEST(SDK_API_TSIOBufferReaderClone)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2822 {
2823   bool test_passed = false;
2824   *pstatus         = REGRESSION_TEST_INPROGRESS;
2825 
2826   TSIOBuffer bufp          = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2827   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2828 
2829   TSIOBufferProduce(bufp, 10);
2830   TSIOBufferReaderConsume(readerp, 5);
2831 
2832   TSIOBufferReader readerp2 = TSIOBufferReaderClone(readerp);
2833 
2834   int64_t reader_avail = TSIOBufferReaderAvail(readerp2);
2835   if (reader_avail == 5) {
2836     SDK_RPRINT(test, "TSIOBufferReaderClone", "TestCase1", TC_PASS, "ok");
2837     test_passed = true;
2838   } else {
2839     SDK_RPRINT(test, "TSIOBufferReaderClone", "TestCase1", TC_FAIL, "failed");
2840   }
2841 
2842   // Status of the whole test
2843   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2844   return;
2845 }
2846 
2847 //////////////////////////////////////////////
2848 //       SDK_API_TSIOBuffer
2849 //
2850 // Unit Test for API: TSIOBufferStart
2851 //                    TSIOBufferReaderStart
2852 //////////////////////////////////////////////
2853 
REGRESSION_TEST(SDK_API_TSIOBufferStart)2854 REGRESSION_TEST(SDK_API_TSIOBufferStart)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2855 {
2856   bool test_passed = false;
2857   *pstatus         = REGRESSION_TEST_INPROGRESS;
2858 
2859   TSIOBuffer bufp = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2860 
2861   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2862 
2863   if (TSIOBufferStart(bufp) == TSIOBufferReaderStart(readerp)) {
2864     SDK_RPRINT(test, "TSIOBufferStart", "TestCase1", TC_PASS, "ok");
2865     SDK_RPRINT(test, "TSIOBufferReaderStart", "TestCase1", TC_PASS, "ok");
2866     test_passed = true;
2867   } else {
2868     SDK_RPRINT(test, "TSIOBufferStart", "TestCase1", TC_FAIL, "failed");
2869     SDK_RPRINT(test, "TSIOBufferReaderStart", "TestCase1", TC_FAIL, "failed");
2870   }
2871 
2872   // Status of the whole test
2873   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2874   return;
2875 }
2876 
2877 //////////////////////////////////////////////
2878 //       SDK_API_TSIOBuffer
2879 //
2880 // Unit Test for API: TSIOBufferCopy
2881 //                    TSIOBufferWrite
2882 //                    TSIOBufferReaderCopy
2883 //////////////////////////////////////////////
2884 
REGRESSION_TEST(SDK_API_TSIOBufferCopy)2885 REGRESSION_TEST(SDK_API_TSIOBufferCopy)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2886 {
2887   bool test_passed = false;
2888   *pstatus         = REGRESSION_TEST_INPROGRESS;
2889 
2890   char input_buf[] = "This is the test for TSIOBufferCopy, TSIOBufferWrite, TSIOBufferReaderCopy";
2891   char output_buf[1024];
2892   TSIOBuffer bufp  = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2893   TSIOBuffer bufp2 = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2894 
2895   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2896   TSIOBufferWrite(bufp, input_buf, (strlen(input_buf) + 1));
2897   TSIOBufferCopy(bufp2, readerp, (strlen(input_buf) + 1), 0);
2898   TSIOBufferReaderCopy(readerp, output_buf, (strlen(input_buf) + 1));
2899 
2900   if (strcmp(input_buf, output_buf) == 0) {
2901     SDK_RPRINT(test, "TSIOBufferWrite", "TestCase1", TC_PASS, "ok");
2902     SDK_RPRINT(test, "TSIOBufferCopy", "TestCase1", TC_PASS, "ok");
2903     SDK_RPRINT(test, "TSIOBufferReaderCopy", "TestCase1", TC_PASS, "ok");
2904     test_passed = true;
2905   } else {
2906     SDK_RPRINT(test, "TSIOBufferWrite", "TestCase1", TC_FAIL, "failed");
2907     SDK_RPRINT(test, "TSIOBufferCopy", "TestCase1", TC_FAIL, "failed");
2908     SDK_RPRINT(test, "TSIOBufferReaderCopy", "TestCase1", TC_FAIL, "failed");
2909   }
2910 
2911   // Status of the whole test
2912   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2913   return;
2914 }
2915 
2916 //////////////////////////////////////////////
2917 //       SDK_API_TSIOBuffer
2918 //
2919 // Unit Test for API: TSIOBuffer
2920 //                    TSIOBufferWrite
2921 //                    TSIOBufferReaderCopy
2922 //////////////////////////////////////////////
2923 
REGRESSION_TEST(SDK_API_TSIOBufferBlockReadAvail)2924 REGRESSION_TEST(SDK_API_TSIOBufferBlockReadAvail)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2925 {
2926   bool test_passed_1 = false;
2927   bool test_passed_2 = false;
2928   *pstatus           = REGRESSION_TEST_INPROGRESS;
2929 
2930   int i           = 10000;
2931   TSIOBuffer bufp = TSIOBufferCreate();
2932   TSIOBufferWrite(bufp, reinterpret_cast<char *>(&i), sizeof(int));
2933   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2934 
2935   int64_t avail_write, avail_read;
2936 
2937   // TODO: This is probably not correct any more.
2938   TSIOBufferBlock blockp = TSIOBufferStart(bufp);
2939 
2940   if ((TSIOBufferBlockWriteStart(blockp, &avail_write) - TSIOBufferBlockReadStart(blockp, readerp, &avail_read)) == sizeof(int)) {
2941     SDK_RPRINT(test, "TSIOBufferBlockReadStart", "TestCase1", TC_PASS, "ok");
2942     SDK_RPRINT(test, "TSIOBufferBlockWriteStart", "TestCase1", TC_PASS, "ok");
2943     test_passed_1 = true;
2944   } else {
2945     SDK_RPRINT(test, "TSIOBufferBlockReadStart", "TestCase1", TC_FAIL, "failed");
2946     SDK_RPRINT(test, "TSIOBufferBlockWriteStart", "TestCase1", TC_FAIL, "failed");
2947   }
2948 
2949   if ((TSIOBufferBlockReadAvail(blockp, readerp) + TSIOBufferBlockWriteAvail(blockp)) == 32768) {
2950     SDK_RPRINT(test, "TSIOBufferBlockReadAvail", "TestCase1", TC_PASS, "ok");
2951     SDK_RPRINT(test, "TSIOBufferBlockWriteAvail", "TestCase1", TC_PASS, "ok");
2952     test_passed_2 = true;
2953   } else {
2954     SDK_RPRINT(test, "TSIOBufferBlockReadAvail", "TestCase1", TC_FAIL, "failed");
2955     SDK_RPRINT(test, "TSIOBufferBlockWriteAvail", "TestCase1", TC_FAIL, "failed");
2956   }
2957 
2958   if (test_passed_1 && test_passed_2) {
2959     *pstatus = REGRESSION_TEST_PASSED;
2960   } else {
2961     *pstatus = REGRESSION_TEST_FAILED;
2962   }
2963 
2964   return;
2965 }
2966 
2967 //////////////////////////////////////////////////
2968 //       SDK_API_TSIOBuffer
2969 //
2970 // Unit Test for API: TSIOBufferBlockNext
2971 //////////////////////////////////////////////////
2972 
REGRESSION_TEST(SDK_API_TSIOBufferBlockNext)2973 REGRESSION_TEST(SDK_API_TSIOBufferBlockNext)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2974 {
2975   bool test_passed = false;
2976   *pstatus         = REGRESSION_TEST_INPROGRESS;
2977 
2978   int i           = 10000;
2979   TSIOBuffer bufp = TSIOBufferCreate();
2980   TSIOBufferWrite(bufp, reinterpret_cast<char *>(&i), sizeof(int));
2981 
2982   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2983   TSIOBufferBlock blockp   = TSIOBufferReaderStart(readerp);
2984 
2985   // TODO: This is probably not the best of regression tests right now ...
2986   // Note that this assumes block size is > sizeof(int) bytes.
2987   if (TSIOBufferBlockNext(blockp) == nullptr) {
2988     SDK_RPRINT(test, "TSIOBufferBlockNext", "TestCase1", TC_PASS, "ok");
2989     test_passed = true;
2990   } else {
2991     SDK_RPRINT(test, "TSIOBufferBlockNext", "TestCase1", TC_FAIL, "fail");
2992   }
2993 
2994   if (test_passed) {
2995     *pstatus = REGRESSION_TEST_PASSED;
2996   } else {
2997     *pstatus = REGRESSION_TEST_FAILED;
2998   }
2999 
3000   return;
3001 }
3002 
REGRESSION_TEST(SDK_API_TSContSchedule)3003 REGRESSION_TEST(SDK_API_TSContSchedule)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
3004 {
3005   *pstatus = REGRESSION_TEST_INPROGRESS;
3006 
3007   // For asynchronous APIs, use static vars to store test and pstatus
3008   SDK_ContSchedule_test    = test;
3009   SDK_ContSchedule_pstatus = pstatus;
3010 
3011   TSCont contp  = TSContCreate(cont_schedule_handler, TSMutexCreate());
3012   TSCont contp2 = TSContCreate(cont_schedule_handler, TSMutexCreate());
3013 
3014   // Test Case 1: schedule immediate
3015   TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
3016 
3017   // Test Case 2: schedule in 10ms
3018   TSContScheduleOnPool(contp2, 10, TS_THREAD_POOL_NET);
3019 }
3020 
3021 //////////////////////////////////////////////////////////////////////////////
3022 //     SDK_API_HttpHookAdd
3023 //
3024 // Unit Test for API: TSHttpHookAdd
3025 //                    TSHttpTxnReenable
3026 //                    TSHttpTxnClientIPGet
3027 //                    TSHttpTxnServerIPGet
3028 //                    TSHttpTxnIncomingAddrGet
3029 //                    TSHttpTxnClientAddrGet
3030 //                    TSHttpTxnClientReqGet
3031 //                    TSHttpTxnClientRespGet
3032 //                    TSHttpTxnServerReqGet
3033 //                    TSHttpTxnServerRespGet
3034 //                    TSHttpTxnNextHopAddrGet
3035 //                    TSHttpTxnClientProtocolStackGet
3036 //                    TSHttpTxnClientProtocolStackContains
3037 //                    TSHttpTxnServerSsnTransactionCount
3038 //////////////////////////////////////////////////////////////////////////////
3039 
3040 #define HTTP_HOOK_TEST_REQUEST_ID 1
3041 
3042 struct SocketTest {
3043   RegressionTest *regtest;
3044   int *pstatus;
3045   SocketServer *os;
3046   ClientTxn *browser;
3047   int hook_mask;
3048   int reenable_mask;
3049   bool test_client_ip_get;
3050   bool test_client_incoming_port_get;
3051   bool test_client_remote_port_get;
3052   bool test_client_req_get;
3053   bool test_client_resp_get;
3054   bool test_server_ip_get;
3055   bool test_server_req_get;
3056   bool test_server_resp_get;
3057   bool test_next_hop_ip_get;
3058   bool test_client_protocol_stack_get;
3059   bool test_client_protocol_stack_contains;
3060 
3061   unsigned int magic;
3062 };
3063 
3064 // This func is called by us from mytest_handler to test TSHttpTxnClientIPGet
3065 static int
checkHttpTxnClientIPGet(SocketTest * test,void * data)3066 checkHttpTxnClientIPGet(SocketTest *test, void *data)
3067 {
3068   sockaddr const *ptr;
3069   in_addr_t ip;
3070   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3071   in_addr_t actual_ip = htonl(INADDR_LOOPBACK); /* 127.0.0.1 is expected because the client is on the same machine */
3072 
3073   ptr = TSHttpTxnClientAddrGet(txnp);
3074   if (ptr == nullptr || INADDR_ANY == (ip = ats_ip4_addr_cast(ptr))) {
3075     test->test_client_ip_get = false;
3076     SDK_RPRINT(test->regtest, "TSHttpTxnClientIPGet", "TestCase1", TC_FAIL, "TSHttpTxnClientIPGet returns 0 %s",
3077                ptr ? "address" : "pointer");
3078     return TS_EVENT_CONTINUE;
3079   }
3080 
3081   if (ip == actual_ip) {
3082     test->test_client_ip_get = true;
3083     SDK_RPRINT(test->regtest, "TSHttpTxnClientIPGet", "TestCase1", TC_PASS, "ok [%0.8x]", ip);
3084   } else {
3085     test->test_client_ip_get = false;
3086     SDK_RPRINT(test->regtest, "TSHttpTxnClientIPGet", "TestCase1", TC_FAIL, "Value's Mismatch [expected %.8x got %.8x]", actual_ip,
3087                ip);
3088   }
3089   return TS_EVENT_CONTINUE;
3090 }
3091 
3092 // This func is called by us from mytest_handler to check for TSHttpTxnClientProtocolStackGet
3093 static int
checkHttpTxnClientProtocolStackGet(SocketTest * test,void * data)3094 checkHttpTxnClientProtocolStackGet(SocketTest *test, void *data)
3095 {
3096   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3097   const char *results[10];
3098   int count = 0;
3099   TSHttpTxnClientProtocolStackGet(txnp, 10, results, &count);
3100   // Should return results[0] = "http/1.0", results[1] = "tcp", results[2] = "ipv4"
3101   test->test_client_protocol_stack_get = true;
3102   if (count != 3) {
3103     test->test_client_protocol_stack_get = false;
3104     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "count should be 3 is %d", count);
3105   } else if (strcmp(results[0], "http/1.0") != 0) {
3106     test->test_client_protocol_stack_get = false;
3107     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "results[0] should be http/1.0 is %s",
3108                results[0]);
3109   } else if (strcmp(results[1], "tcp") != 0) {
3110     test->test_client_protocol_stack_get = false;
3111     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "results[1] should be tcp is %s",
3112                results[1]);
3113   } else if (strcmp(results[2], "ipv4") != 0) {
3114     test->test_client_protocol_stack_get = false;
3115     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "results[2] should be ipv4 is %s",
3116                results[2]);
3117   } else {
3118     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_PASS, "ok stack_size=%d", count);
3119   }
3120   return TS_EVENT_CONTINUE;
3121 }
3122 
3123 // This func is called by us from mytest_handler to check for TSHttpTxnClientProtocolStackContains
3124 static int
checkHttpTxnClientProtocolStackContains(SocketTest * test,void * data)3125 checkHttpTxnClientProtocolStackContains(SocketTest *test, void *data)
3126 {
3127   TSHttpTxn txnp                            = static_cast<TSHttpTxn>(data);
3128   const char *ret_tag                       = TSHttpTxnClientProtocolStackContains(txnp, "tcp");
3129   test->test_client_protocol_stack_contains = true;
3130   if (ret_tag) {
3131     const char *normalized_tag = TSNormalizedProtocolTag("tcp");
3132     if (normalized_tag != ret_tag) {
3133       SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase1", TC_FAIL,
3134                  "contains tcp, but normalized tag is wrong");
3135     } else {
3136       SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase1", TC_PASS, "ok tcp");
3137     }
3138   } else {
3139     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase1", TC_FAIL, "missing tcp");
3140     test->test_client_protocol_stack_contains = false;
3141   }
3142   ret_tag = TSHttpTxnClientProtocolStackContains(txnp, "udp");
3143   if (!ret_tag) {
3144     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase2", TC_PASS, "ok no udp");
3145   } else {
3146     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase2", TC_FAIL, "faulty udp report");
3147     test->test_client_protocol_stack_contains = false;
3148   }
3149   return TS_EVENT_CONTINUE;
3150 }
3151 
3152 // This func is called by us from mytest_handler to check for TSHttpTxnNextHopIPGet
3153 static int
checkHttpTxnNextHopIPGet(SocketTest * test,void * data)3154 checkHttpTxnNextHopIPGet(SocketTest *test, void *data)
3155 {
3156   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3157   in_addr_t actual_ip = htonl(INADDR_LOOPBACK); /* 127.0.0.1 is expected because the client is on the same machine */
3158   sockaddr const *ptr;
3159   in_addr_t nexthopip;
3160 
3161   ptr = TSHttpTxnNextHopAddrGet(txnp);
3162   if (ptr == nullptr || (nexthopip = ats_ip4_addr_cast(ptr)) == 0) {
3163     test->test_next_hop_ip_get = false;
3164     SDK_RPRINT(test->regtest, "TSHttpTxnNextHopIPGet", "TestCase1", TC_FAIL, "TSHttpTxnNextHopIPGet returns 0 %s",
3165                ptr ? "address" : "pointer");
3166     return TS_EVENT_CONTINUE;
3167   }
3168 
3169   if (nexthopip == actual_ip) {
3170     test->test_next_hop_ip_get = true;
3171     SDK_RPRINT(test->regtest, "TSHttpTxnNextHopIPGet", "TestCase1", TC_PASS, "ok");
3172   } else {
3173     test->test_next_hop_ip_get = false;
3174     SDK_RPRINT(test->regtest, "TSHttpTxnNextHopIPGet", "TestCase1", TC_FAIL, "Value's Mismatch [expected %0.8x got %0.8x]",
3175                actual_ip, nexthopip);
3176   }
3177 
3178   return TS_EVENT_CONTINUE;
3179 }
3180 
3181 // This func is called by us from mytest_handler to test TSHttpTxnServerIPGet
3182 static int
checkHttpTxnServerIPGet(SocketTest * test,void * data)3183 checkHttpTxnServerIPGet(SocketTest *test, void *data)
3184 {
3185   sockaddr const *ptr;
3186   in_addr_t ip;
3187   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3188   in_addr_t actual_ip = htonl(INADDR_LOOPBACK); /* 127.0.0.1 is expected because the client is on the same machine */
3189 
3190   ptr = TSHttpTxnServerAddrGet(txnp);
3191   if (nullptr == ptr || 0 == (ip = ats_ip4_addr_cast(ptr))) {
3192     test->test_server_ip_get = false;
3193     SDK_RPRINT(test->regtest, "TSHttpTxnServerIPGet", "TestCase1", TC_FAIL, "TSHttpTxnServerIPGet returns 0 %s",
3194                ptr ? "address" : "pointer");
3195     return TS_EVENT_CONTINUE;
3196   }
3197 
3198   if (ip == actual_ip) {
3199     test->test_server_ip_get = true;
3200     SDK_RPRINT(test->regtest, "TSHttpTxnServerIPGet", "TestCase1", TC_PASS, "ok");
3201   } else {
3202     test->test_server_ip_get = false;
3203     SDK_RPRINT(test->regtest, "TSHttpTxnServerIPGet", "TestCase1", TC_FAIL, "Value's Mismatch");
3204   }
3205 
3206   return TS_EVENT_CONTINUE;
3207 }
3208 
3209 // This func is called by us from mytest_handler to test TSHttpTxnIncomingAddrGet
3210 static int
checkHttpTxnIncomingAddrGet(SocketTest * test,void * data)3211 checkHttpTxnIncomingAddrGet(SocketTest *test, void *data)
3212 {
3213   uint16_t port;
3214   const HttpProxyPort *proxy_port = HttpProxyPort::findHttp(AF_INET);
3215   TSHttpTxn txnp                  = static_cast<TSHttpTxn>(data);
3216   sockaddr const *ptr             = TSHttpTxnIncomingAddrGet(txnp);
3217 
3218   if (nullptr == proxy_port) {
3219     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingPortGet", "TestCase1", TC_FAIL,
3220                "TSHttpTxnIncomingAddrGet failed to find configured HTTP port.");
3221     test->test_client_incoming_port_get = false;
3222     return TS_EVENT_CONTINUE;
3223   }
3224   if (nullptr == ptr) {
3225     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingPortGet", "TestCase1", TC_FAIL, "TSHttpTxnIncomingAddrGet returns 0 pointer");
3226     test->test_client_incoming_port_get = false;
3227     return TS_EVENT_CONTINUE;
3228   }
3229   port = ats_ip_port_host_order(ptr);
3230 
3231   TSDebug(UTDBG_TAG, "TS HTTP port = %x, Txn incoming client port %x", proxy_port->m_port, port);
3232 
3233   if (port == proxy_port->m_port) {
3234     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingAddrGet", "TestCase1", TC_PASS, "ok");
3235     test->test_client_incoming_port_get = true;
3236   } else {
3237     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingAddrGet", "TestCase1", TC_FAIL,
3238                "Value's Mismatch. From Function: %d  Expected value: %d", port, proxy_port->m_port);
3239     test->test_client_incoming_port_get = false;
3240   }
3241   return TS_EVENT_CONTINUE;
3242 }
3243 
3244 // This func is called by us from mytest_handler to test TSHttpTxnClientAddrGet
3245 static int
checkHttpTxnClientAddrGet(SocketTest * test,void * data)3246 checkHttpTxnClientAddrGet(SocketTest *test, void *data)
3247 {
3248   uint16_t port;
3249   uint16_t browser_port;
3250   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3251   sockaddr const *ptr = TSHttpTxnClientAddrGet(txnp);
3252 
3253   browser_port = test->browser->local_port;
3254 
3255   if (nullptr == ptr) {
3256     SDK_RPRINT(test->regtest, "TSHttpTxnClientClientAddrGet", "TestCase2", TC_FAIL, "TSHttpTxnClientAddrGet returned 0 pointer.");
3257     test->test_client_remote_port_get = false;
3258     return TS_EVENT_CONTINUE;
3259   }
3260 
3261   port = ats_ip_port_host_order(ptr);
3262   TSDebug(UTDBG_TAG, "Browser port = %x, Txn remote port = %x", browser_port, port);
3263 
3264   if (port == browser_port) {
3265     SDK_RPRINT(test->regtest, "TSHttpTxnClientAddrGet", "TestCase1", TC_PASS, "ok");
3266     test->test_client_remote_port_get = true;
3267   } else {
3268     SDK_RPRINT(test->regtest, "TSHttpTxnClientAddrGet", "TestCase1", TC_FAIL,
3269                "Value's Mismatch. From Function: %d Expected Value: %d", port, browser_port);
3270     test->test_client_remote_port_get = false;
3271   }
3272   return TS_EVENT_CONTINUE;
3273 }
3274 
3275 // This func is called by us from mytest_handler to test TSHttpTxnClientReqGet
3276 static int
checkHttpTxnClientReqGet(SocketTest * test,void * data)3277 checkHttpTxnClientReqGet(SocketTest *test, void *data)
3278 {
3279   TSMBuffer bufp;
3280   TSMLoc mloc;
3281   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3282 
3283   if (TSHttpTxnClientReqGet(txnp, &bufp, &mloc) != TS_SUCCESS) {
3284     test->test_client_req_get = false;
3285     SDK_RPRINT(test->regtest, "TSHttpTxnClientReqGet", "TestCase1", TC_FAIL, "Unable to get handle to client request");
3286     return TS_EVENT_CONTINUE;
3287   }
3288 
3289   if ((bufp == reinterpret_cast<TSMBuffer>(&((HttpSM *)txnp)->t_state.hdr_info.client_request)) &&
3290       (mloc == reinterpret_cast<TSMLoc>(((HttpSM *)txnp)->t_state.hdr_info.client_request.m_http))) {
3291     test->test_client_req_get = true;
3292     SDK_RPRINT(test->regtest, "TSHttpTxnClientReqGet", "TestCase1", TC_PASS, "ok");
3293   } else {
3294     test->test_client_req_get = false;
3295     SDK_RPRINT(test->regtest, "TSHttpTxnClientReqGet", "TestCase1", TC_FAIL, "Value's Mismatch");
3296   }
3297 
3298   return TS_EVENT_CONTINUE;
3299 }
3300 
3301 // This func is called by us from mytest_handler to test TSHttpTxnClientRespGet
3302 static int
checkHttpTxnClientRespGet(SocketTest * test,void * data)3303 checkHttpTxnClientRespGet(SocketTest *test, void *data)
3304 {
3305   TSMBuffer bufp;
3306   TSMLoc mloc;
3307   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3308 
3309   if (TSHttpTxnClientRespGet(txnp, &bufp, &mloc) != TS_SUCCESS) {
3310     test->test_client_resp_get = false;
3311     SDK_RPRINT(test->regtest, "TSHttpTxnClientRespGet", "TestCase1", TC_FAIL, "Unable to get handle to client response");
3312     return TS_EVENT_CONTINUE;
3313   }
3314 
3315   if ((bufp == reinterpret_cast<TSMBuffer>(&((HttpSM *)txnp)->t_state.hdr_info.client_response)) &&
3316       (mloc == reinterpret_cast<TSMLoc>(((HttpSM *)txnp)->t_state.hdr_info.client_response.m_http))) {
3317     test->test_client_resp_get = true;
3318     SDK_RPRINT(test->regtest, "TSHttpTxnClientRespGet", "TestCase1", TC_PASS, "ok");
3319   } else {
3320     test->test_client_resp_get = false;
3321     SDK_RPRINT(test->regtest, "TSHttpTxnClientRespGet", "TestCase1", TC_FAIL, "Value's Mismatch");
3322   }
3323 
3324   return TS_EVENT_CONTINUE;
3325 }
3326 
3327 // This func is called by us from mytest_handler to test TSHttpTxnServerReqGet
3328 static int
checkHttpTxnServerReqGet(SocketTest * test,void * data)3329 checkHttpTxnServerReqGet(SocketTest *test, void *data)
3330 {
3331   TSMBuffer bufp;
3332   TSMLoc mloc;
3333   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3334 
3335   if (TSHttpTxnServerReqGet(txnp, &bufp, &mloc) != TS_SUCCESS) {
3336     test->test_server_req_get = false;
3337     SDK_RPRINT(test->regtest, "TSHttpTxnServerReqGet", "TestCase1", TC_FAIL, "Unable to get handle to server request");
3338     return TS_EVENT_CONTINUE;
3339   }
3340 
3341   if ((bufp == reinterpret_cast<TSMBuffer>(&((HttpSM *)txnp)->t_state.hdr_info.server_request)) &&
3342       (mloc == reinterpret_cast<TSMLoc>(((HttpSM *)txnp)->t_state.hdr_info.server_request.m_http))) {
3343     test->test_server_req_get = true;
3344     SDK_RPRINT(test->regtest, "TSHttpTxnServerReqGet", "TestCase1", TC_PASS, "ok");
3345   } else {
3346     test->test_server_req_get = false;
3347     SDK_RPRINT(test->regtest, "TSHttpTxnServerReqGet", "TestCase1", TC_FAIL, "Value's Mismatch");
3348   }
3349 
3350   return TS_EVENT_CONTINUE;
3351 }
3352 
3353 // This func is called by us from mytest_handler to test TSHttpTxnServerRespGet
3354 static int
checkHttpTxnServerRespGet(SocketTest * test,void * data)3355 checkHttpTxnServerRespGet(SocketTest *test, void *data)
3356 {
3357   TSMBuffer bufp;
3358   TSMLoc mloc;
3359   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3360 
3361   if (TSHttpTxnServerRespGet(txnp, &bufp, &mloc) != TS_SUCCESS) {
3362     test->test_server_resp_get = false;
3363     SDK_RPRINT(test->regtest, "TSHttpTxnServerRespGet", "TestCase1", TC_FAIL, "Unable to get handle to server response");
3364     return TS_EVENT_CONTINUE;
3365   }
3366 
3367   if ((bufp == reinterpret_cast<TSMBuffer>(&((HttpSM *)txnp)->t_state.hdr_info.server_response)) &&
3368       (mloc == reinterpret_cast<TSMLoc>(((HttpSM *)txnp)->t_state.hdr_info.server_response.m_http))) {
3369     test->test_server_resp_get = true;
3370     SDK_RPRINT(test->regtest, "TSHttpTxnServerRespGet", "TestCase1", TC_PASS, "ok");
3371   } else {
3372     test->test_server_resp_get = false;
3373     SDK_RPRINT(test->regtest, "TSHttpTxnServerRespGet", "TestCase1", TC_FAIL, "Value's Mismatch");
3374   }
3375 
3376   return TS_EVENT_CONTINUE;
3377 }
3378 
3379 // This func is called by us from mytest_handler to test TSHttpTxnServerSsnTransactionCount
3380 static int
checkHttpTxnServerSsnTransactionCount(SocketTest * test,void * data)3381 checkHttpTxnServerSsnTransactionCount(SocketTest *test, void *data)
3382 {
3383   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3384 
3385   int count = TSHttpTxnServerSsnTransactionCount(txnp);
3386   if (count < 0) {
3387     SDK_RPRINT(test->regtest, "TSHttpTxnServerSsnTransactionCount", "TestCase1", TC_FAIL, "invalid count value '%d'", count);
3388   } else {
3389     SDK_RPRINT(test->regtest, "TSHttpTxnServerSsnTransactionCount", "TestCase1", TC_PASS, "ok - count='%d'", count);
3390   }
3391 
3392   return count;
3393 }
3394 
3395 // This func is called both by us when scheduling EVENT_IMMEDIATE
3396 // And by HTTP SM for registered hooks
3397 // Depending on the timing of the DNS response, OS_DNS can happen before or after CACHE_LOOKUP.
3398 static int
mytest_handler(TSCont contp,TSEvent event,void * data)3399 mytest_handler(TSCont contp, TSEvent event, void *data)
3400 {
3401   SocketTest *test = static_cast<SocketTest *>(TSContDataGet(contp));
3402   if (test == nullptr) {
3403     if ((event == TS_EVENT_IMMEDIATE) || (event == TS_EVENT_TIMEOUT)) {
3404       return 0;
3405     }
3406     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3407     return 0;
3408   }
3409   TSAssert(test->magic == MAGIC_ALIVE);
3410   TSAssert(test->browser->magic == MAGIC_ALIVE);
3411 
3412   switch (event) {
3413   case TS_EVENT_HTTP_TXN_START:
3414     if (test->hook_mask == 0) {
3415       test->hook_mask |= 1;
3416     }
3417 
3418     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3419     test->reenable_mask |= 1;
3420     break;
3421 
3422   case TS_EVENT_HTTP_READ_REQUEST_HDR:
3423     if (test->hook_mask == 1) {
3424       test->hook_mask |= 2;
3425     }
3426     TSSkipRemappingSet(static_cast<TSHttpTxn>(data), 1);
3427     checkHttpTxnClientReqGet(test, data);
3428 
3429     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3430     test->reenable_mask |= 2;
3431     break;
3432 
3433   case TS_EVENT_HTTP_OS_DNS:
3434     if (test->hook_mask == 3 || test->hook_mask == 7) {
3435       test->hook_mask |= 8;
3436     }
3437 
3438     checkHttpTxnIncomingAddrGet(test, data);
3439     checkHttpTxnClientAddrGet(test, data);
3440 
3441     checkHttpTxnClientIPGet(test, data);
3442     checkHttpTxnServerIPGet(test, data);
3443 
3444     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3445     test->reenable_mask |= 8;
3446     break;
3447 
3448   case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
3449     if (test->hook_mask == 3 || test->hook_mask == 11) {
3450       test->hook_mask |= 4;
3451     }
3452     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3453     test->reenable_mask |= 4;
3454     break;
3455 
3456   case TS_EVENT_HTTP_SEND_REQUEST_HDR:
3457     if (test->hook_mask == 15) {
3458       test->hook_mask |= 16;
3459     }
3460 
3461     checkHttpTxnServerReqGet(test, data);
3462     checkHttpTxnNextHopIPGet(test, data);
3463     checkHttpTxnClientProtocolStackContains(test, data);
3464     checkHttpTxnClientProtocolStackGet(test, data);
3465 
3466     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3467     test->reenable_mask |= 16;
3468     break;
3469 
3470   case TS_EVENT_HTTP_READ_RESPONSE_HDR:
3471     if (test->hook_mask == 31) {
3472       test->hook_mask |= 32;
3473     }
3474     checkHttpTxnServerRespGet(test, data);
3475     checkHttpTxnServerSsnTransactionCount(test, data);
3476 
3477     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3478     test->reenable_mask |= 32;
3479     break;
3480 
3481   case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
3482     if (test->hook_mask == 63) {
3483       test->hook_mask |= 64;
3484     }
3485 
3486     checkHttpTxnClientRespGet(test, data);
3487     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3488     test->reenable_mask |= 64;
3489     break;
3490 
3491   case TS_EVENT_HTTP_TXN_CLOSE:
3492     if (test->hook_mask == 127) {
3493       test->hook_mask |= 128;
3494     }
3495 
3496     TSHttpTxnReenable(static_cast<TSHttpTxn>(data), TS_EVENT_HTTP_CONTINUE);
3497     test->reenable_mask |= 128;
3498     break;
3499 
3500   case TS_EVENT_IMMEDIATE:
3501   case TS_EVENT_TIMEOUT:
3502     /* Browser still waiting the response ? */
3503     if (test->browser->status == REQUEST_INPROGRESS) {
3504       TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
3505     }
3506     /* Browser got the response. test is over. clean up */
3507     else {
3508       /* Note: response is available using test->browser->response pointer */
3509       if ((test->browser->status == REQUEST_SUCCESS) && (test->hook_mask == 255)) {
3510         *(test->pstatus) = REGRESSION_TEST_PASSED;
3511         SDK_RPRINT(test->regtest, "TSHttpHookAdd", "TestCase1", TC_PASS, "ok");
3512 
3513       } else {
3514         *(test->pstatus) = REGRESSION_TEST_FAILED;
3515         SDK_RPRINT(test->regtest, "TSHttpHookAdd", "TestCase1", TC_FAIL, "Hooks not called or request failure. Hook mask = %d\n %s",
3516                    test->hook_mask, test->browser->response);
3517       }
3518 
3519       if (test->reenable_mask == 255) {
3520         SDK_RPRINT(test->regtest, "TSHttpTxnReenable", "TestCase1", TC_PASS, "ok");
3521 
3522       } else {
3523         *(test->pstatus) = REGRESSION_TEST_FAILED;
3524         SDK_RPRINT(test->regtest, "TSHttpTxnReenable", "TestCase1", TC_FAIL, "Txn not re-enabled properly");
3525       }
3526 
3527       if ((test->test_client_ip_get != true) || (test->test_client_incoming_port_get != true) ||
3528           (test->test_client_remote_port_get != true) || (test->test_client_req_get != true) ||
3529           (test->test_client_resp_get != true) || (test->test_server_ip_get != true) || (test->test_server_req_get != true) ||
3530           (test->test_server_resp_get != true) || (test->test_next_hop_ip_get != true)) {
3531         *(test->pstatus) = REGRESSION_TEST_FAILED;
3532       }
3533       // transaction is over. clean up.
3534       synclient_txn_delete(test->browser);
3535       synserver_delete(test->os);
3536       test->os = nullptr;
3537 
3538       test->magic = MAGIC_DEAD;
3539       TSfree(test);
3540       TSContDataSet(contp, nullptr);
3541     }
3542     break;
3543 
3544   default:
3545     *(test->pstatus) = REGRESSION_TEST_FAILED;
3546     SDK_RPRINT(test->regtest, "TSHttpHookAdd", "TestCase1", TC_FAIL, "Unexpected event %d", event);
3547     break;
3548   }
3549 
3550   return TS_EVENT_IMMEDIATE;
3551 }
3552 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpHookAdd)3553 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpHookAdd)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
3554 {
3555   *pstatus = REGRESSION_TEST_INPROGRESS;
3556 
3557   TSCont cont          = TSContCreate(mytest_handler, TSMutexCreate());
3558   SocketTest *socktest = static_cast<SocketTest *>(TSmalloc(sizeof(SocketTest)));
3559 
3560   socktest->regtest                       = test;
3561   socktest->pstatus                       = pstatus;
3562   socktest->hook_mask                     = 0;
3563   socktest->reenable_mask                 = 0;
3564   socktest->test_client_ip_get            = false;
3565   socktest->test_client_incoming_port_get = false;
3566   socktest->test_client_req_get           = false;
3567   socktest->test_client_resp_get          = false;
3568   socktest->test_server_ip_get            = false;
3569   socktest->test_server_req_get           = false;
3570   socktest->test_server_resp_get          = false;
3571   socktest->test_next_hop_ip_get          = false;
3572   socktest->magic                         = MAGIC_ALIVE;
3573   TSContDataSet(cont, socktest);
3574 
3575   /* Register to HTTP hooks that are called in case of a cache MISS */
3576   TSHttpHookAdd(TS_HTTP_TXN_START_HOOK, cont);
3577   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont);
3578   TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, cont);
3579   TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont);
3580   TSHttpHookAdd(TS_HTTP_SEND_REQUEST_HDR_HOOK, cont);
3581   TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, cont);
3582   TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont);
3583   TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, cont);
3584 
3585   /* Create a new synthetic server */
3586   socktest->os = synserver_create(SYNSERVER_LISTEN_PORT);
3587   synserver_start(socktest->os);
3588 
3589   /* Create a client transaction */
3590   socktest->browser = synclient_txn_create();
3591   char *request     = generate_request(HTTP_HOOK_TEST_REQUEST_ID); // this request has a no-cache that prevents caching
3592   synclient_txn_send_request(socktest->browser, request);
3593   TSfree(request);
3594 
3595   /* Wait until transaction is done */
3596   if (socktest->browser->status == REQUEST_INPROGRESS) {
3597     TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
3598   }
3599 
3600   return;
3601 }
3602 
3603 //////////////////////////////////////////////
3604 //       SDK_API_TSUrl
3605 //
3606 // Unit Test for API: TSUrlCreate
3607 //                    TSUrlSchemeGet
3608 //                    TSUrlSchemeSet
3609 //                    TSUrlUserGet
3610 //                    TSUrlUserSet
3611 //                    TSUrlPasswordGet
3612 //                    TSUrlPasswordSet
3613 //                    TSUrlHostGet
3614 //                    TSUrlHostSet
3615 //                    TSUrlPortGet
3616 //                    TSUrlPortSet
3617 //                    TSUrlPathGet
3618 //                    TSUrlPathSet
3619 //                    TSUrlHttpParamsGet
3620 //                    TSUrlHttpParamsSet
3621 //                    TSUrlHttpQueryGet
3622 //                    TSUrlHttpQuerySet
3623 //                    TSUrlHttpFragmentGet
3624 //                    TSUrlHttpFragmentSet
3625 //                    TSUrlCopy
3626 //                    TSUrlClone
3627 //                    TSUrlStringGet
3628 //                    TSUrlPrint
3629 //                    TSUrlLengthGet
3630 //                    TSUrlFtpTypeGet
3631 //                    TSUrlFtpTypeSet
3632 //////////////////////////////////////////////
3633 
3634 char *
test_url_print(TSMBuffer bufp,TSMLoc hdr_loc)3635 test_url_print(TSMBuffer bufp, TSMLoc hdr_loc)
3636 {
3637   TSIOBuffer output_buffer;
3638   TSIOBufferReader reader;
3639   int64_t total_avail;
3640 
3641   TSIOBufferBlock block;
3642   const char *block_start;
3643   int64_t block_avail;
3644 
3645   char *output_string;
3646   int output_len;
3647 
3648   output_buffer = TSIOBufferCreate();
3649 
3650   if (!output_buffer) {
3651     TSError("[InkAPITest] couldn't allocate IOBuffer");
3652   }
3653 
3654   reader = TSIOBufferReaderAlloc(output_buffer);
3655 
3656   /* This will print  just MIMEFields and not
3657      the http request line */
3658   TSUrlPrint(bufp, hdr_loc, output_buffer);
3659 
3660   /* Find out how the big the complete header is by
3661      seeing the total bytes in the buffer.  We need to
3662      look at the buffer rather than the first block to
3663      see the size of the entire header */
3664   total_avail = TSIOBufferReaderAvail(reader);
3665 
3666   /* Allocate the string with an extra byte for the string
3667      terminator */
3668   output_string = static_cast<char *>(TSmalloc(total_avail + 1));
3669   output_len    = 0;
3670 
3671   /* We need to loop over all the buffer blocks to make
3672      sure we get the complete header since the header can
3673      be in multiple blocks */
3674   block = TSIOBufferReaderStart(reader);
3675   while (block) {
3676     block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
3677 
3678     /* We'll get a block pointer back even if there is no data
3679        left to read so check for this condition and break out of
3680        the loop. A block with no data to read means we've exhausted
3681        buffer of data since if there was more data on a later
3682        block in the chain, this block would have been skipped over */
3683     if (block_avail == 0) {
3684       break;
3685     }
3686 
3687     memcpy(output_string + output_len, block_start, block_avail);
3688     output_len += block_avail;
3689 
3690     /* Consume the data so that we get to the next block */
3691     TSIOBufferReaderConsume(reader, block_avail);
3692 
3693     /* Get the next block now that we've consumed the
3694        data off the last block */
3695     block = TSIOBufferReaderStart(reader);
3696   }
3697 
3698   /* Terminate the string */
3699   output_string[output_len] = '\0';
3700   output_len++;
3701 
3702   /* Free up the TSIOBuffer that we used to print out the header */
3703   TSIOBufferReaderFree(reader);
3704   TSIOBufferDestroy(output_buffer);
3705 
3706   return output_string;
3707 }
3708 
REGRESSION_TEST(SDK_API_TSUrl)3709 REGRESSION_TEST(SDK_API_TSUrl)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
3710 {
3711   TSMBuffer bufp1 = (TSMBuffer) nullptr;
3712   TSMBuffer bufp2 = (TSMBuffer) nullptr;
3713   TSMBuffer bufp3 = (TSMBuffer) nullptr;
3714   TSMLoc url_loc1;
3715   TSMLoc url_loc2;
3716   TSMLoc url_loc3;
3717   const char *scheme = TS_URL_SCHEME_HTTP;
3718   const char *scheme_get;
3719   const char *user = "yyy";
3720   const char *user_get;
3721   const char *password = "xxx";
3722   const char *password_get;
3723   const char *host = "www.example.com";
3724   const char *host_get;
3725   int port = 2021;
3726   char port_char[10];
3727   int port_get     = 80;
3728   const char *path = "about/overview.html";
3729   const char *path_get;
3730   const char *params = "abcdef";
3731   const char *params_get;
3732   const char *query = "name=xxx";
3733   const char *query_get;
3734   const char *fragment = "yyy";
3735   const char *fragment_get;
3736   char *url_expected_string;
3737   char *url_string_from_1     = (char *)nullptr;
3738   char *url_string_from_2     = (char *)nullptr;
3739   char *url_string_from_3     = (char *)nullptr;
3740   char *url_string_from_print = (char *)nullptr;
3741   int url_expected_length;
3742   int url_length_from_1;
3743   int url_length_from_2;
3744   int type = 'a';
3745   int type_get;
3746   int tmp_len;
3747 
3748   bool test_passed_create   = false;
3749   bool test_passed_scheme   = false;
3750   bool test_passed_user     = false;
3751   bool test_passed_password = false;
3752   bool test_passed_host     = false;
3753   bool test_passed_port     = false;
3754   bool test_passed_path     = false;
3755   bool test_passed_params   = false;
3756   bool test_passed_query    = false;
3757   bool test_passed_fragment = false;
3758   bool test_passed_copy     = false;
3759   bool test_passed_clone    = false;
3760   bool test_passed_string1  = false;
3761   bool test_passed_string2  = false;
3762   bool test_passed_print    = false;
3763   bool test_passed_length1  = false;
3764   bool test_passed_length2  = false;
3765   bool test_passed_type     = false;
3766 
3767   int length;
3768 
3769   *pstatus = REGRESSION_TEST_INPROGRESS;
3770 
3771   // Initialization
3772   memset(port_char, 0, 10);
3773   snprintf(port_char, sizeof(port_char), "%d", port);
3774 
3775   // HTTP URL
3776 
3777   url_expected_length =
3778     strlen(scheme) + strlen("://") + ((user == nullptr) ? 0 : strlen(user)) +
3779     ((password == nullptr) ? ((user == nullptr) ? 0 : strlen("@")) : strlen(":") + strlen(password) + strlen("@")) + strlen(host) +
3780     ((port == 80) ? 0 : strlen(port_char) + strlen(":")) + strlen("/") + strlen(path) +
3781     ((params == nullptr) ? 0 : strlen(";") + strlen(params)) + ((query == nullptr) ? 0 : strlen("?") + strlen(query)) +
3782     ((fragment == nullptr) ? 0 : strlen("#") + strlen(fragment));
3783 
3784   size_t len          = url_expected_length + 1;
3785   url_expected_string = static_cast<char *>(TSmalloc(len * sizeof(char)));
3786   memset(url_expected_string, 0, url_expected_length + 1);
3787   snprintf(url_expected_string, len, "%s://%s%s%s%s%s%s%s/%s%s%s%s%s%s%s", scheme, ((user == nullptr) ? "" : user),
3788            ((password == nullptr) ? "" : ":"), ((password == nullptr) ? "" : password),
3789            (((user == nullptr) && (password == nullptr)) ? "" : "@"), host, ((port == 80) ? "" : ":"),
3790            ((port == 80) ? "" : port_char), ((path == nullptr) ? "" : path), ((params == nullptr) ? "" : ";"),
3791            ((params == nullptr) ? "" : params), ((query == nullptr) ? "" : "?"), ((query == nullptr) ? "" : query),
3792            ((fragment == nullptr) ? "" : "#"), ((fragment == nullptr) ? "" : fragment));
3793 
3794   // Set Functions
3795 
3796   bufp1 = TSMBufferCreate();
3797   if (TSUrlCreate(bufp1, &url_loc1) != TS_SUCCESS) {
3798     // Cannot proceed with tests.
3799     SDK_RPRINT(test, "TSUrlCreate", "TestCase1", TC_FAIL, "unable to create URL within buffer.");
3800     goto print_results;
3801   }
3802   // Scheme
3803   if (TSUrlSchemeSet(bufp1, url_loc1, scheme, -1) != TS_SUCCESS) {
3804     SDK_RPRINT(test, "TSUrlSchemeSet", "TestCase1", TC_FAIL, "TSUrlSchemeSet Returned TS_ERROR");
3805   } else {
3806     scheme_get = TSUrlSchemeGet(bufp1, url_loc1, &length);
3807     if (scheme_get != nullptr && strncmp(scheme_get, scheme, length) == 0) {
3808       SDK_RPRINT(test, "TSUrlSchemeSet&Get", "TestCase1", TC_PASS, "ok");
3809       test_passed_scheme = true;
3810     } else {
3811       SDK_RPRINT(test, "TSUrlSchemeSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3812     }
3813   }
3814 
3815   // User
3816   if (TSUrlUserSet(bufp1, url_loc1, user, -1) != TS_SUCCESS) {
3817     SDK_RPRINT(test, "TSUrlUserSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3818   } else {
3819     user_get = TSUrlUserGet(bufp1, url_loc1, &length);
3820     if (user_get != nullptr && strncmp(user_get, user, length) == 0) {
3821       SDK_RPRINT(test, "TSUrlUserSet&Get", "TestCase1", TC_PASS, "ok");
3822       test_passed_user = true;
3823     } else {
3824       SDK_RPRINT(test, "TSUrlUserSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3825     }
3826   }
3827 
3828   // Password
3829   if (TSUrlPasswordSet(bufp1, url_loc1, password, -1) != TS_SUCCESS) {
3830     SDK_RPRINT(test, "TSUrlPasswordSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3831   } else {
3832     password_get = TSUrlPasswordGet(bufp1, url_loc1, &length);
3833     if (password_get != nullptr && strncmp(password_get, password, length) == 0) {
3834       SDK_RPRINT(test, "TSUrlPasswordSet&Get", "TestCase1", TC_PASS, "ok");
3835       test_passed_password = true;
3836     } else {
3837       SDK_RPRINT(test, "TSUrlPasswordSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3838     }
3839   }
3840 
3841   // Host
3842   if (TSUrlHostSet(bufp1, url_loc1, host, -1) != TS_SUCCESS) {
3843     SDK_RPRINT(test, "TSUrlHostSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3844   } else {
3845     host_get = TSUrlHostGet(bufp1, url_loc1, &length);
3846     if (host_get != nullptr && strncmp(host_get, host, length) == 0) {
3847       SDK_RPRINT(test, "TSUrlHostSet&Get", "TestCase1", TC_PASS, "ok");
3848       test_passed_host = true;
3849     } else {
3850       SDK_RPRINT(test, "TSUrlHostSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3851     }
3852   }
3853 
3854   // Port
3855   if (TSUrlPortSet(bufp1, url_loc1, port) != TS_SUCCESS) {
3856     SDK_RPRINT(test, "TSUrlPortSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3857   } else {
3858     port_get = TSUrlPortGet(bufp1, url_loc1);
3859     if (port_get == port) {
3860       SDK_RPRINT(test, "TSUrlPortSet&Get", "TestCase1", TC_PASS, "ok");
3861       test_passed_port = true;
3862     } else {
3863       SDK_RPRINT(test, "TSUrlPortSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3864     }
3865   }
3866 
3867   // Path
3868   if (TSUrlPathSet(bufp1, url_loc1, path, -1) != TS_SUCCESS) {
3869     SDK_RPRINT(test, "TSUrlPathSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3870   } else {
3871     path_get = TSUrlPathGet(bufp1, url_loc1, &length);
3872     if (path_get != nullptr && strncmp(path, path_get, length) == 0) {
3873       SDK_RPRINT(test, "TSUrlPathSet&Get", "TestCase1", TC_PASS, "ok");
3874       test_passed_path = true;
3875     } else {
3876       SDK_RPRINT(test, "TSUrlPathSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3877     }
3878   }
3879 
3880   // Params
3881   if (TSUrlHttpParamsSet(bufp1, url_loc1, params, -1) != TS_SUCCESS) {
3882     SDK_RPRINT(test, "TSUrlHttpParamsSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3883   } else {
3884     params_get = TSUrlHttpParamsGet(bufp1, url_loc1, &length);
3885     if (params_get != nullptr && strncmp(params, params_get, length) == 0) {
3886       SDK_RPRINT(test, "TSUrlHttpParamsSet&Get", "TestCase1", TC_PASS, "ok");
3887       test_passed_params = true;
3888     } else {
3889       SDK_RPRINT(test, "TSUrlHttpParamsSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3890     }
3891   }
3892 
3893   // Query
3894   if (TSUrlHttpQuerySet(bufp1, url_loc1, query, -1) != TS_SUCCESS) {
3895     SDK_RPRINT(test, "TSUrlHttpQuerySet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3896   } else {
3897     query_get = TSUrlHttpQueryGet(bufp1, url_loc1, &length);
3898     if (query_get != nullptr && strncmp(query, query_get, length) == 0) {
3899       SDK_RPRINT(test, "TSUrlHttpQuerySet&Get", "TestCase1", TC_PASS, "ok");
3900       test_passed_query = true;
3901     } else {
3902       SDK_RPRINT(test, "TSUrlHttpQuerySet&Get", "TestCase1", TC_FAIL, "Values don't match");
3903     }
3904   }
3905 
3906   // Fragments
3907   if (TSUrlHttpFragmentSet(bufp1, url_loc1, fragment, -1) != TS_SUCCESS) {
3908     SDK_RPRINT(test, "TSUrlHttpFragmentSet", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3909   } else {
3910     fragment_get = TSUrlHttpFragmentGet(bufp1, url_loc1, &length);
3911     if (fragment_get != nullptr && strncmp(fragment, fragment_get, length) == 0) {
3912       SDK_RPRINT(test, "TSUrlHttpFragmentSet&Get", "TestCase1", TC_PASS, "ok");
3913       test_passed_fragment = true;
3914     } else {
3915       SDK_RPRINT(test, "TSUrlHttpFragmentSet&Get", "TestCase1", TC_FAIL, "Values don't match");
3916     }
3917   }
3918 
3919   // Length
3920   url_length_from_1 = TSUrlLengthGet(bufp1, url_loc1);
3921   if (url_length_from_1 == url_expected_length) {
3922     SDK_RPRINT(test, "TSUrlLengthGet", "TestCase1", TC_PASS, "ok");
3923     test_passed_length1 = true;
3924   } else {
3925     SDK_RPRINT(test, "TSUrlLengthGet", "TestCase1", TC_FAIL, "Values don't match");
3926   }
3927 
3928   // String
3929   url_string_from_1 = TSUrlStringGet(bufp1, url_loc1, &tmp_len);
3930   if (strcmp(url_string_from_1, url_expected_string) == 0) {
3931     SDK_RPRINT(test, "TSUrlStringGet", "TestCase1", TC_PASS, "ok");
3932     test_passed_string1 = true;
3933   } else {
3934     SDK_RPRINT(test, "TSUrlStringGet", "TestCase1", TC_FAIL, "Values don't match");
3935   }
3936 
3937   // Copy
3938   bufp2 = TSMBufferCreate();
3939   if (TSUrlCreate(bufp2, &url_loc2) != TS_SUCCESS) {
3940     // Cannot proceed with tests.
3941     SDK_RPRINT(test, "TSUrlCreate", "TestCase2", TC_FAIL, "unable to create URL within buffer for TSUrlCopy.");
3942     goto print_results;
3943   }
3944   if (TSUrlCopy(bufp2, url_loc2, bufp1, url_loc1) == TS_ERROR) {
3945     SDK_RPRINT(test, "TSUrlCopy", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3946   } else {
3947     // Length Test Case 2
3948     url_length_from_2 = TSUrlLengthGet(bufp2, url_loc2);
3949     if (url_length_from_2 == url_expected_length) {
3950       SDK_RPRINT(test, "TSUrlLengthGet", "TestCase2", TC_PASS, "ok");
3951       test_passed_length2 = true;
3952     } else {
3953       SDK_RPRINT(test, "TSUrlCopy", "TestCase1", TC_FAIL, "Values don't match");
3954     }
3955 
3956     // String Test Case 2
3957     url_string_from_2 = TSUrlStringGet(bufp2, url_loc2, &tmp_len);
3958     if (strcmp(url_string_from_2, url_expected_string) == 0) {
3959       SDK_RPRINT(test, "TSUrlStringGet", "TestCase2", TC_PASS, "ok");
3960       test_passed_string2 = true;
3961     } else {
3962       SDK_RPRINT(test, "TSUrlStringGet", "TestCase2", TC_FAIL, "Values don't match");
3963     }
3964 
3965     // Copy Test Case
3966     if (strcmp(url_string_from_1, url_string_from_2) == 0) {
3967       SDK_RPRINT(test, "TSUrlCopy", "TestCase1", TC_PASS, "ok");
3968       test_passed_copy = true;
3969     } else {
3970       SDK_RPRINT(test, "TSUrlCopy", "TestCase1", TC_FAIL, "Values Don't Match");
3971     }
3972   }
3973 
3974   // Clone
3975   bufp3 = TSMBufferCreate();
3976   if (TSUrlClone(bufp3, bufp1, url_loc1, &url_loc3) != TS_SUCCESS) {
3977     SDK_RPRINT(test, "TSUrlClone", "TestCase1", TC_FAIL, "Returned TS_ERROR");
3978   } else {
3979     // String Test Case 2
3980     url_string_from_3 = TSUrlStringGet(bufp3, url_loc3, &tmp_len);
3981     // Copy Test Case
3982     if (strcmp(url_string_from_1, url_string_from_3) == 0) {
3983       SDK_RPRINT(test, "TSUrlClone", "TestCase1", TC_PASS, "ok");
3984       test_passed_clone = true;
3985     } else {
3986       SDK_RPRINT(test, "TSUrlClone", "TestCase1", TC_FAIL, "Values Don't Match");
3987     }
3988   }
3989 
3990   // UrlPrint
3991   url_string_from_print = test_url_print(bufp1, url_loc1);
3992   if (url_string_from_print == nullptr) {
3993     SDK_RPRINT(test, "TSUrlPrint", "TestCase1", TC_FAIL, "TSUrlPrint doesn't return TS_SUCCESS");
3994   } else {
3995     if (strcmp(url_string_from_print, url_expected_string) == 0) {
3996       SDK_RPRINT(test, "TSUrlPrint", "TestCase1", TC_PASS, "ok");
3997       test_passed_print = true;
3998     } else {
3999       SDK_RPRINT(test, "TSUrlPrint", "TestCase1", TC_FAIL, "TSUrlPrint doesn't return TS_SUCCESS");
4000     }
4001     TSfree(url_string_from_print);
4002   }
4003 
4004   if (TSUrlFtpTypeSet(bufp1, url_loc1, type) != TS_SUCCESS) {
4005     SDK_RPRINT(test, "TSUrlFtpTypeSet", "TestCase1", TC_FAIL, "TSUrlFtpTypeSet Returned TS_ERROR");
4006   } else {
4007     type_get = TSUrlFtpTypeGet(bufp1, url_loc1);
4008     if (type_get == type) {
4009       SDK_RPRINT(test, "TSUrlFtpTypeSet&Get", "TestCase1", TC_PASS, "ok");
4010       test_passed_type = true;
4011     } else {
4012       SDK_RPRINT(test, "TSUrlFtpTypeSet&Get", "TestCase1", TC_FAIL, "Values don't match");
4013     }
4014   }
4015 
4016   SDK_RPRINT(test, "TSUrlCreate", "TestCase1&2", TC_PASS, "ok");
4017   TSHandleMLocRelease(bufp1, TS_NULL_MLOC, url_loc1);
4018   TSHandleMLocRelease(bufp2, TS_NULL_MLOC, url_loc2);
4019   TSHandleMLocRelease(bufp3, TS_NULL_MLOC, url_loc3);
4020   test_passed_create = true;
4021 
4022 print_results:
4023   TSfree(url_expected_string);
4024   if (url_string_from_1 != nullptr) {
4025     TSfree(url_string_from_1);
4026   }
4027   if (url_string_from_2 != nullptr) {
4028     TSfree(url_string_from_2);
4029   }
4030   if (url_string_from_3 != nullptr) {
4031     TSfree(url_string_from_3);
4032   }
4033   if (bufp1 != nullptr) {
4034     TSMBufferDestroy(bufp1);
4035   }
4036   if (bufp2 != nullptr) {
4037     TSMBufferDestroy(bufp2);
4038   }
4039   if (bufp3 != nullptr) {
4040     TSMBufferDestroy(bufp3);
4041   }
4042   if ((test_passed_create == false) || (test_passed_scheme == false) || (test_passed_user == false) ||
4043       (test_passed_password == false) || (test_passed_host == false) || (test_passed_port == false) ||
4044       (test_passed_path == false) || (test_passed_params == false) || (test_passed_query == false) ||
4045       (test_passed_fragment == false) || (test_passed_copy == false) || (test_passed_clone == false) ||
4046       (test_passed_string1 == false) || (test_passed_string2 == false) || (test_passed_print == false) ||
4047       (test_passed_length1 == false) || (test_passed_length2 == false) || (test_passed_type == false)) {
4048     /*** Debugging the test itself....
4049     (test_passed_create == false)?printf("test_passed_create is false\n"):printf("");
4050     (test_passed_destroy == false)?printf("test_passed_destroy is false\n"):printf("");
4051     (test_passed_user == false)?printf("test_passed_user is false\n"):printf("");
4052     (test_passed_password == false)?printf("test_passed_password is false\n"):printf("");
4053     (test_passed_host == false)?printf("test_passed_host is false\n"):printf("");
4054     (test_passed_port == false)?printf("test_passed_port is false\n"):printf("");
4055     (test_passed_path == false)?printf("test_passed_path is false\n"):printf("");
4056     (test_passed_params == false)?printf("test_passed_params is false\n"):printf("");
4057     (test_passed_query == false)?printf("test_passed_query is false\n"):printf("");
4058     (test_passed_fragment == false)?printf("test_passed_fragment is false\n"):printf("");
4059     (test_passed_copy == false)?printf("test_passed_copy is false\n"):printf("");
4060     (test_passed_string1 == false)?printf("test_passed_string1 is false\n"):printf("");
4061     (test_passed_string2 == false)?printf("test_passed_string2 is false\n"):printf("");
4062     (test_passed_length1 == false)?printf("test_passed_length1 is false\n"):printf("");
4063     (test_passed_length2 == false)?printf("test_passed_length2 is false\n"):printf("");
4064     (test_passed_type == false)?printf("test_passed_type is false\n"):printf("");
4065     .....***********/
4066     *pstatus = REGRESSION_TEST_FAILED;
4067   } else {
4068     *pstatus = REGRESSION_TEST_PASSED;
4069   }
4070 }
4071 
4072 //////////////////////////////////////////////
4073 //       SDK_API_TSHttpHdr
4074 //
4075 // Unit Test for API: TSHttpHdrCreate
4076 //                    TSHttpHdrCopy
4077 //                    TSHttpHdrClone
4078 //                    TSHttpHdrDestroy
4079 //                    TSHttpHdrLengthGet
4080 //                    TSHttpHdrMethodGet
4081 //                    TSHttpHdrMethodSet
4082 //                    TSHttpHdrPrint
4083 //                    TSHttpHdrReasonGet
4084 //                    TSHttpHdrReasonLookup
4085 //                    TSHttpHdrReasonSet
4086 //                    TSHttpHdrStatusGet
4087 //                    TSHttpHdrStatusSet
4088 //                    TSHttpHdrTypeGet
4089 //                    TSHttpHdrUrlGet
4090 //                    TSHttpHdrUrlSet
4091 //////////////////////////////////////////////
4092 
4093 /**
4094  * If you change value of any constant in this function then reflect that change in variable expected_iobuf.
4095  */
REGRESSION_TEST(SDK_API_TSHttpHdr)4096 REGRESSION_TEST(SDK_API_TSHttpHdr)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
4097 {
4098   TSMBuffer bufp1 = (TSMBuffer) nullptr;
4099   TSMBuffer bufp2 = (TSMBuffer) nullptr;
4100   TSMBuffer bufp3 = (TSMBuffer) nullptr;
4101   TSMBuffer bufp4 = (TSMBuffer) nullptr;
4102 
4103   TSMLoc hdr_loc1 = (TSMLoc) nullptr;
4104   TSMLoc hdr_loc2 = (TSMLoc) nullptr;
4105   TSMLoc hdr_loc3 = (TSMLoc) nullptr;
4106   TSMLoc hdr_loc4 = (TSMLoc) nullptr;
4107 
4108   TSHttpType hdr1type;
4109   TSHttpType hdr2type;
4110 
4111   const char *methodGet;
4112 
4113   TSMLoc url_loc;
4114   TSMLoc url_loc_Get;
4115   const char *url_host = "www.example.com";
4116   int url_port         = 2345;
4117   const char *url_path = "abcd/efg/hij.htm";
4118 
4119   const char *response_reason = "aefa";
4120   const char *response_reason_get;
4121 
4122   TSHttpStatus status_get;
4123 
4124   int version_major = 2;
4125   int version_minor = 1;
4126   int version_get;
4127 
4128   /* TSHttpType type1; unused: lv */
4129   /* TSHttpType type2; unused: lv */
4130   const char *method1;
4131   const char *method2;
4132   int length1;
4133   int length2;
4134   TSMLoc url_loc1;
4135   TSMLoc url_loc2;
4136   /* int version1; unused: lv */
4137   /* int version2; unused: lv */
4138 
4139   int length;
4140   const char *expected_iobuf = "GET http://www.example.com:2345/abcd/efg/hij.htm HTTP/2.1\r\n\r\n";
4141   int actual_length;
4142   int expected_length;
4143   bool test_passed_Http_Hdr_Create        = false;
4144   bool test_passed_Http_Hdr_Type          = false;
4145   bool test_passed_Http_Hdr_Method        = false;
4146   bool test_passed_Http_Hdr_Url           = false;
4147   bool test_passed_Http_Hdr_Status        = false;
4148   bool test_passed_Http_Hdr_Reason        = false;
4149   bool test_passed_Http_Hdr_Reason_Lookup = false;
4150   bool test_passed_Http_Hdr_Version       = false;
4151   bool test_passed_Http_Hdr_Copy          = false;
4152   bool test_passed_Http_Hdr_Clone         = false;
4153   bool test_passed_Http_Hdr_Length        = false;
4154   bool test_passed_Http_Hdr_Print         = false;
4155   bool test_passed_Http_Hdr_Destroy       = false;
4156   bool try_print_function                 = true;
4157   bool test_buffer_created                = true;
4158 
4159   *pstatus = REGRESSION_TEST_INPROGRESS;
4160 
4161   bufp1 = TSMBufferCreate();
4162   bufp2 = TSMBufferCreate();
4163   bufp3 = TSMBufferCreate();
4164   bufp4 = TSMBufferCreate();
4165 
4166   // Create
4167   if (test_buffer_created == true) {
4168     hdr_loc1 = TSHttpHdrCreate(bufp1);
4169     hdr_loc2 = TSHttpHdrCreate(bufp2);
4170     hdr_loc3 = TSHttpHdrCreate(bufp3);
4171     SDK_RPRINT(test, "TSHttpHdrCreate", "TestCase1&2&3", TC_PASS, "ok");
4172     test_passed_Http_Hdr_Create = true;
4173   } else {
4174     SDK_RPRINT(test, "TSHttpHdrCreate", "All Test Cases", TC_FAIL, "Cannot run test as unable to allocate MBuffers");
4175   }
4176 
4177   // Type
4178   if (test_passed_Http_Hdr_Create == true) {
4179     if ((TSHttpHdrTypeSet(bufp1, hdr_loc1, TS_HTTP_TYPE_REQUEST) == TS_ERROR) ||
4180         (TSHttpHdrTypeSet(bufp2, hdr_loc2, TS_HTTP_TYPE_RESPONSE) == TS_ERROR)) {
4181       SDK_RPRINT(test, "TSHttpHdrTypeSet", "TestCase1|2", TC_FAIL, "TSHttpHdrTypeSet returns TS_ERROR");
4182     } else {
4183       hdr1type = TSHttpHdrTypeGet(bufp1, hdr_loc1);
4184       hdr2type = TSHttpHdrTypeGet(bufp2, hdr_loc2);
4185       if ((hdr1type == TS_HTTP_TYPE_REQUEST) && (hdr2type == TS_HTTP_TYPE_RESPONSE)) {
4186         SDK_RPRINT(test, "TSHttpHdrTypeSet&Get", "TestCase1&2", TC_PASS, "ok");
4187         test_passed_Http_Hdr_Type = true;
4188       } else {
4189         SDK_RPRINT(test, "TSHttpHdrTypeSet&Get", "TestCase1&2", TC_FAIL, "Values mismatch");
4190       }
4191     }
4192   } else {
4193     SDK_RPRINT(test, "TSHttpHdrTypeSet&Get", "All Test Case", TC_FAIL, "Cannot run test as Header Creation Test failed");
4194   }
4195 
4196   // Method
4197   if (test_passed_Http_Hdr_Type == true) {
4198     if (TSHttpHdrMethodSet(bufp1, hdr_loc1, TS_HTTP_METHOD_GET, -1) == TS_ERROR) {
4199       SDK_RPRINT(test, "TSHttpHdrMethodSet&Get", "TestCase1", TC_FAIL, "TSHttpHdrMethodSet returns TS_ERROR");
4200     } else {
4201       methodGet = TSHttpHdrMethodGet(bufp1, hdr_loc1, &length);
4202       if ((strncmp(methodGet, TS_HTTP_METHOD_GET, length) == 0) && (length == static_cast<int>(strlen(TS_HTTP_METHOD_GET)))) {
4203         SDK_RPRINT(test, "TSHttpHdrMethodSet&Get", "TestCase1", TC_PASS, "ok");
4204         test_passed_Http_Hdr_Method = true;
4205       } else {
4206         SDK_RPRINT(test, "TSHttpHdrMethodSet&Get", "TestCase1", TC_FAIL, "Value's mismatch");
4207       }
4208     }
4209   } else {
4210     SDK_RPRINT(test, "TSHttpHdrMethodSet&Get", "All Test Case", TC_FAIL, "Cannot run test as Header's Type cannot be set");
4211   }
4212 
4213   // Url
4214   if (test_passed_Http_Hdr_Type == true) {
4215     if (TSUrlCreate(bufp1, &url_loc) != TS_SUCCESS) {
4216       SDK_RPRINT(test, "TSHttpHdrUrlSet&Get", "TestCase1", TC_FAIL, "Cannot run test as TSUrlCreate returns TS_ERROR");
4217     } else {
4218       if (TSHttpHdrUrlSet(bufp1, hdr_loc1, url_loc) == TS_ERROR) {
4219         SDK_RPRINT(test, "TSHttpHdrUrlSet&Get", "TestCase1", TC_FAIL, "TSHttpHdrUrlSet returns TS_ERROR");
4220       } else {
4221         if (TSHttpHdrUrlGet(bufp1, hdr_loc1, &url_loc_Get) != TS_SUCCESS) {
4222           SDK_RPRINT(test, "TSHttpHdrUrlSet&Get", "TestCase1", TC_FAIL, "TSHttpHdrUrlGet returns TS_ERROR");
4223         } else {
4224           if (url_loc == url_loc_Get) {
4225             SDK_RPRINT(test, "TSHttpHdrUrlSet&Get", "TestCase1", TC_PASS, "ok");
4226             test_passed_Http_Hdr_Url = true;
4227           } else {
4228             SDK_RPRINT(test, "TSHttpHdrUrlSet&Get", "TestCase1", TC_FAIL, "Value's mismatch");
4229           }
4230           if (TSHandleMLocRelease(bufp1, hdr_loc1, url_loc_Get) == TS_ERROR) {
4231             SDK_RPRINT(test, "TSHandleMLocRelease", "", TC_FAIL, "Unable to release handle to URL");
4232           }
4233         }
4234       }
4235 
4236       // Fill up the URL for Copy Test Case.
4237       if (TSUrlSchemeSet(bufp1, url_loc, TS_URL_SCHEME_HTTP, -1) == TS_ERROR) {
4238         SDK_RPRINT(test, "TSUrlSchemeSet", "", TC_FAIL, "Unable to set scheme in URL in the HTTP Header");
4239         try_print_function = false;
4240       }
4241       if (TSUrlHostSet(bufp1, url_loc, url_host, -1) == TS_ERROR) {
4242         SDK_RPRINT(test, "TSUrlHostSet", "", TC_FAIL, "Unable to set host in URL in the HTTP Header");
4243         try_print_function = false;
4244       }
4245       if (TSUrlPortSet(bufp1, url_loc, url_port) == TS_ERROR) {
4246         SDK_RPRINT(test, "TSUrlPortSet", "", TC_FAIL, "Unable to set port in URL in the HTTP Header");
4247         try_print_function = false;
4248       }
4249       if (TSUrlPathSet(bufp1, url_loc, url_path, -1) == TS_ERROR) {
4250         SDK_RPRINT(test, "TSUrlPathSet", "", TC_FAIL, "Unable to set path in URL in the HTTP Header");
4251         try_print_function = false;
4252       }
4253       if (TSHandleMLocRelease(bufp1, hdr_loc1, url_loc) == TS_ERROR) {
4254         SDK_RPRINT(test, "TSHandleMLocRelease", "", TC_FAIL, "Unable to release handle to URL");
4255       }
4256     }
4257   } else {
4258     SDK_RPRINT(test, "TSHttpHdrUrlSet&Get", "All Test Case", TC_FAIL, "Cannot run test as Header's Type cannot be set");
4259   }
4260 
4261   // Reason
4262   if (test_passed_Http_Hdr_Type == true) {
4263     if (TSHttpHdrReasonSet(bufp2, hdr_loc2, response_reason, -1) == TS_ERROR) {
4264       SDK_RPRINT(test, "TSHttpHdrReasonSet&Get", "TestCase1", TC_FAIL, "TSHttpHdrReasonSet returns TS_ERROR");
4265     } else {
4266       response_reason_get = TSHttpHdrReasonGet(bufp2, hdr_loc2, &length);
4267       if ((strncmp(response_reason_get, response_reason, length) == 0) && (length == static_cast<int>(strlen(response_reason)))) {
4268         SDK_RPRINT(test, "TSHttpHdrReasonSet&Get", "TestCase1", TC_PASS, "ok");
4269         test_passed_Http_Hdr_Reason = true;
4270       } else {
4271         SDK_RPRINT(test, "TSHttpHdrReasonSet&Get", "TestCase1", TC_FAIL, "Value's mismatch");
4272       }
4273     }
4274   } else {
4275     SDK_RPRINT(test, "TSHttpHdrReasonSet&Get", "All Test Case", TC_FAIL, "Cannot run test as Header's Type cannot be set");
4276   }
4277 
4278   // Status
4279   if (test_passed_Http_Hdr_Type == true) {
4280     if (TSHttpHdrStatusSet(bufp2, hdr_loc2, TS_HTTP_STATUS_OK) == TS_ERROR) {
4281       SDK_RPRINT(test, "TSHttpHdrStatusSet&Get", "TestCase1", TC_FAIL, "TSHttpHdrStatusSet returns TS_ERROR");
4282     } else {
4283       status_get = TSHttpHdrStatusGet(bufp2, hdr_loc2);
4284       if (status_get == TS_HTTP_STATUS_OK) {
4285         SDK_RPRINT(test, "TSHttpHdrStatusSet&Get", "TestCase1", TC_PASS, "ok");
4286         test_passed_Http_Hdr_Status = true;
4287       } else {
4288         SDK_RPRINT(test, "TSHttpHdrStatusSet&Get", "TestCase1", TC_FAIL, "Value's mismatch");
4289       }
4290     }
4291   } else {
4292     SDK_RPRINT(test, "TSHttpHdrStatusSet&Get", "All Test Case", TC_FAIL, "Cannot run test as Header's Type cannot be set");
4293   }
4294 
4295   // Version
4296   if (test_passed_Http_Hdr_Type == true) {
4297     if (TSHttpHdrVersionSet(bufp1, hdr_loc1, TS_HTTP_VERSION(version_major, version_minor)) == TS_ERROR) {
4298       SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "TestCase1", TC_FAIL, "TSHttpHdrVersionSet returns TS_ERROR");
4299     } else {
4300       version_get = TSHttpHdrVersionGet(bufp1, hdr_loc1);
4301       if ((version_major == TS_HTTP_MAJOR(version_get)) && (version_minor == TS_HTTP_MINOR(version_get))) {
4302         SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "TestCase1", TC_PASS, "ok");
4303         test_passed_Http_Hdr_Version = true;
4304       } else {
4305         SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "TestCase1", TC_FAIL, "Value's mismatch");
4306       }
4307     }
4308   } else {
4309     SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "All Test Case", TC_FAIL, "Cannot run test as Header's Type cannot be set");
4310   }
4311 
4312   if (test_passed_Http_Hdr_Version == true) {
4313     if (TSHttpHdrVersionSet(bufp2, hdr_loc2, TS_HTTP_VERSION(version_major, version_minor)) == TS_ERROR) {
4314       SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "TestCase2", TC_FAIL, "TSHttpHdrVersionSet returns TS_ERROR");
4315       test_passed_Http_Hdr_Version = false;
4316     } else {
4317       version_get = TSHttpHdrVersionGet(bufp2, hdr_loc2);
4318       if ((version_major == TS_HTTP_MAJOR(version_get)) && (version_minor == TS_HTTP_MINOR(version_get))) {
4319         SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "TestCase2", TC_PASS, "ok");
4320       } else {
4321         SDK_RPRINT(test, "TSHttpHdrVersionSet&Get", "TestCase2", TC_FAIL, "Value's mismatch");
4322         test_passed_Http_Hdr_Version = false;
4323       }
4324     }
4325   }
4326   // Reason Lookup
4327   if (strcmp("None", TSHttpHdrReasonLookup(TS_HTTP_STATUS_NONE)) != 0) {
4328     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase1", TC_FAIL, "TSHttpHdrReasonLookup returns Value's mismatch");
4329   } else {
4330     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase1", TC_PASS, "ok");
4331     test_passed_Http_Hdr_Reason_Lookup = true;
4332   }
4333 
4334   if (strcmp("OK", TSHttpHdrReasonLookup(TS_HTTP_STATUS_OK)) != 0) {
4335     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase2", TC_FAIL, "TSHttpHdrReasonLookup returns Value's mismatch");
4336     if (test_passed_Http_Hdr_Reason_Lookup == true) {
4337       test_passed_Http_Hdr_Reason_Lookup = false;
4338     }
4339   } else {
4340     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase2", TC_PASS, "ok");
4341   }
4342 
4343   if (strcmp("Continue", TSHttpHdrReasonLookup(TS_HTTP_STATUS_CONTINUE)) != 0) {
4344     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase3", TC_FAIL, "TSHttpHdrReasonLookup returns Value's mismatch");
4345     if (test_passed_Http_Hdr_Reason_Lookup == true) {
4346       test_passed_Http_Hdr_Reason_Lookup = false;
4347     }
4348   } else {
4349     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase3", TC_PASS, "ok");
4350   }
4351 
4352   if (strcmp("Not Modified", TSHttpHdrReasonLookup(TS_HTTP_STATUS_NOT_MODIFIED)) != 0) {
4353     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase4", TC_FAIL, "TSHttpHdrReasonLookup returns Value's mismatch");
4354     if (test_passed_Http_Hdr_Reason_Lookup == true) {
4355       test_passed_Http_Hdr_Reason_Lookup = false;
4356     }
4357   } else {
4358     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase4", TC_PASS, "ok");
4359   }
4360 
4361   if (strcmp("Early Hints", TSHttpHdrReasonLookup(TS_HTTP_STATUS_EARLY_HINTS)) != 0) {
4362     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase5", TC_FAIL, "TSHttpHdrReasonLookup returns Value's mismatch");
4363     if (test_passed_Http_Hdr_Reason_Lookup == true) {
4364       test_passed_Http_Hdr_Reason_Lookup = false;
4365     }
4366   } else {
4367     SDK_RPRINT(test, "TSHttpHdrReasonLookup", "TestCase5", TC_PASS, "ok");
4368   }
4369 
4370   // Copy
4371   if (test_passed_Http_Hdr_Create == true) {
4372     if (TSHttpHdrCopy(bufp3, hdr_loc3, bufp1, hdr_loc1) == TS_ERROR) {
4373       SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "TSHttpHdrCopy returns TS_ERROR");
4374     } else {
4375       bool flag = true;
4376       // Check the type
4377       if (flag == true) {
4378         TSHttpType type1 = TSHttpHdrTypeGet(bufp1, hdr_loc1);
4379         TSHttpType type2 = TSHttpHdrTypeGet(bufp3, hdr_loc3);
4380 
4381         if (type1 != type2) {
4382           SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Type mismatch in both headers");
4383           flag = false;
4384         }
4385       }
4386       // Check the Version
4387       if (flag == true) {
4388         int version1 = TSHttpHdrVersionGet(bufp1, hdr_loc1);
4389         int version2 = TSHttpHdrVersionGet(bufp3, hdr_loc3);
4390 
4391         if (version1 != version2) {
4392           SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Version mismatch in both headers");
4393           flag = false;
4394         }
4395       }
4396       // Check the Method
4397       if (flag == true) {
4398         method1 = TSHttpHdrMethodGet(bufp1, hdr_loc1, &length1);
4399         method2 = TSHttpHdrMethodGet(bufp3, hdr_loc3, &length2);
4400         if ((length1 != length2) || (strncmp(method1, method2, length1) != 0)) {
4401           SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Method mismatch in both headers");
4402           flag = false;
4403         }
4404       }
4405       // Check the URL
4406       if (flag == true) {
4407         if ((TSHttpHdrUrlGet(bufp1, hdr_loc1, &url_loc1) != TS_SUCCESS) ||
4408             (TSHttpHdrUrlGet(bufp3, hdr_loc3, &url_loc2) != TS_SUCCESS)) {
4409           SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "TSHttpVersionGet returns TS_ERROR");
4410         } else {
4411           const char *scheme1;
4412           const char *scheme2;
4413 
4414           const char *host1;
4415           const char *host2;
4416 
4417           int port1;
4418           int port2;
4419 
4420           const char *path1;
4421           const char *path2;
4422 
4423           // URL Scheme
4424           scheme1 = TSUrlSchemeGet(bufp1, url_loc1, &length1);
4425           scheme2 = TSUrlSchemeGet(bufp3, url_loc2, &length2);
4426           if ((length1 != length2) || (strncmp(scheme1, scheme2, length1) != 0)) {
4427             SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Scheme has different values in both headers");
4428             flag = false;
4429           }
4430 
4431           // URL Host
4432           if (flag == true) {
4433             host1 = TSUrlHostGet(bufp1, url_loc1, &length1);
4434             host2 = TSUrlHostGet(bufp3, url_loc2, &length2);
4435             if ((length1 != length2) || (strncmp(host1, host2, length1) != 0)) {
4436               SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Host has different values in both headers");
4437               flag = false;
4438             }
4439           }
4440           // URL Port
4441           if (flag == true) {
4442             port1 = TSUrlPortGet(bufp1, url_loc1);
4443             port2 = TSUrlPortGet(bufp3, url_loc2);
4444             if (port1 != port2) {
4445               SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Port has different values in both headers");
4446               flag = false;
4447             }
4448           }
4449           // URL Path
4450           if (flag == true) {
4451             path1 = TSUrlPathGet(bufp1, url_loc1, &length1);
4452             path2 = TSUrlPathGet(bufp3, url_loc2, &length2);
4453             if ((path1 != nullptr) && (path2 != nullptr)) {
4454               if ((length1 != length2) || (strncmp(path1, path2, length1) != 0)) {
4455                 SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Path has different values in both headers");
4456                 flag = false;
4457               }
4458             } else {
4459               if (path1 != path2) {
4460                 SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Host has different values in both headers");
4461                 flag = false;
4462               }
4463             }
4464             if ((TSHandleMLocRelease(bufp1, hdr_loc1, url_loc1) == TS_ERROR) ||
4465                 (TSHandleMLocRelease(bufp3, hdr_loc3, url_loc2) == TS_ERROR)) {
4466               SDK_RPRINT(test, "TSHandleMLocRelease", "", TC_FAIL, "Unable to release Handle acquired by TSHttpHdrUrlGet");
4467             }
4468           }
4469 
4470           if (flag == true) {
4471             SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_PASS, "ok");
4472             test_passed_Http_Hdr_Copy = true;
4473           }
4474         }
4475       }
4476     }
4477   } else {
4478     SDK_RPRINT(test, "TSHttpHdrCopy", "All Test Cases", TC_PASS, "Cannot run test as TSHttpHdrCreate has failed");
4479   }
4480 
4481   // Clone
4482   if (test_passed_Http_Hdr_Create == true) {
4483     if (TSHttpHdrClone(bufp4, bufp1, hdr_loc1, &hdr_loc4) != TS_SUCCESS) {
4484       SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "TSHttpHdrClone returns TS_ERROR");
4485     } else {
4486       bool flag = true;
4487       // Check the type
4488       if (flag == true) {
4489         TSHttpType type1 = TSHttpHdrTypeGet(bufp1, hdr_loc1);
4490         TSHttpType type2 = TSHttpHdrTypeGet(bufp4, hdr_loc4);
4491 
4492         if (type1 != type2) {
4493           SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "Type mismatch in both headers");
4494           flag = false;
4495         }
4496       }
4497       // Check the Version
4498       if (flag == true) {
4499         int version1 = TSHttpHdrVersionGet(bufp1, hdr_loc1);
4500         int version2 = TSHttpHdrVersionGet(bufp4, hdr_loc4);
4501 
4502         if (version1 != version2) {
4503           SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "Version mismatch in both headers");
4504           flag = false;
4505         }
4506       }
4507       // Check the Method
4508       if (flag == true) {
4509         method1 = TSHttpHdrMethodGet(bufp1, hdr_loc1, &length1);
4510         method2 = TSHttpHdrMethodGet(bufp4, hdr_loc4, &length2);
4511         if ((length1 != length2) || (strncmp(method1, method2, length1) != 0)) {
4512           SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "Method mismatch in both headers");
4513           flag = false;
4514         }
4515       }
4516       // Check the URL
4517       if (flag == true) {
4518         if ((TSHttpHdrUrlGet(bufp1, hdr_loc1, &url_loc1) != TS_SUCCESS) ||
4519             (TSHttpHdrUrlGet(bufp4, hdr_loc4, &url_loc2) != TS_SUCCESS)) {
4520           SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "TSHttpVersionGet returns TS_ERROR");
4521         } else {
4522           const char *scheme1;
4523           const char *scheme2;
4524 
4525           const char *host1;
4526           const char *host2;
4527 
4528           int port1;
4529           int port2;
4530 
4531           const char *path1;
4532           const char *path2;
4533 
4534           // URL Scheme
4535           scheme1 = TSUrlSchemeGet(bufp1, url_loc1, &length1);
4536           scheme2 = TSUrlSchemeGet(bufp4, url_loc2, &length2);
4537           if ((length1 != length2) || (strncmp(scheme1, scheme2, length1) != 0)) {
4538             SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "Url Scheme has different values in both headers");
4539             flag = false;
4540           }
4541 
4542           // URL Host
4543           if (flag == true) {
4544             host1 = TSUrlHostGet(bufp1, url_loc1, &length1);
4545             host2 = TSUrlHostGet(bufp4, url_loc2, &length2);
4546             if ((length1 != length2) || (strncmp(host1, host2, length1) != 0)) {
4547               SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "Url Host has different values in both headers");
4548               flag = false;
4549             }
4550           }
4551           // URL Port
4552           if (flag == true) {
4553             port1 = TSUrlPortGet(bufp1, url_loc1);
4554             port2 = TSUrlPortGet(bufp4, url_loc2);
4555             if (port1 != port2) {
4556               SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_FAIL, "Url Port has different values in both headers");
4557               flag = false;
4558             }
4559           }
4560           // URL Path
4561           if (flag == true) {
4562             path1 = TSUrlPathGet(bufp1, url_loc1, &length1);
4563             path2 = TSUrlPathGet(bufp4, url_loc2, &length2);
4564             if ((path1 != nullptr) && (path2 != nullptr)) {
4565               if ((length1 != length2) || (strncmp(path1, path2, length1) != 0)) {
4566                 SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Path has different values in both headers");
4567                 flag = false;
4568               }
4569             } else {
4570               if (path1 != path2) {
4571                 SDK_RPRINT(test, "TSHttpHdrCopy", "TestCase1", TC_FAIL, "Url Host has different values in both headers");
4572                 flag = false;
4573               }
4574             }
4575             if ((TSHandleMLocRelease(bufp1, hdr_loc1, url_loc1) == TS_ERROR) ||
4576                 (TSHandleMLocRelease(bufp4, hdr_loc4, url_loc2) == TS_ERROR)) {
4577               SDK_RPRINT(test, "TSHandleMLocRelease", "", TC_FAIL, "Unable to release Handle acquired by TSHttpHdrUrlGet");
4578             }
4579           }
4580 
4581           if (flag == true) {
4582             SDK_RPRINT(test, "TSHttpHdrClone", "TestCase1", TC_PASS, "ok");
4583             test_passed_Http_Hdr_Clone = true;
4584           }
4585         }
4586       }
4587     }
4588   } else {
4589     SDK_RPRINT(test, "TSHttpHdrClone", "All Test Cases", TC_PASS, "Cannot run test as TSHttpHdrCreate has failed");
4590   }
4591 
4592   // LengthGet
4593   if (test_passed_Http_Hdr_Create == true) {
4594     actual_length    = TSHttpHdrLengthGet(bufp1, hdr_loc1);
4595     TSIOBuffer iobuf = TSIOBufferCreate();
4596     TSHttpHdrPrint(bufp1, hdr_loc1, iobuf);
4597     TSIOBufferReader iobufreader = TSIOBufferReaderAlloc(iobuf);
4598 
4599     expected_length = TSIOBufferReaderAvail(iobufreader);
4600     if (actual_length == expected_length) {
4601       SDK_RPRINT(test, "TSHttpHdrLengthGet", "TestCase1", TC_PASS, "ok");
4602       test_passed_Http_Hdr_Length = true;
4603     } else {
4604       SDK_RPRINT(test, "TSHttpHdrLengthGet", "TestCase1", TC_FAIL, "Incorrect value returned.");
4605     }
4606 
4607     // Print.
4608     if ((test_passed_Http_Hdr_Method == true) && (test_passed_Http_Hdr_Url == true) && (test_passed_Http_Hdr_Version == true) &&
4609         (test_passed_Http_Hdr_Length == true) && (try_print_function == true)) {
4610       char *actual_iobuf = nullptr;
4611 
4612       actual_iobuf = static_cast<char *>(TSmalloc((actual_length + 1) * sizeof(char)));
4613 
4614       if (actual_iobuf == nullptr) {
4615         SDK_RPRINT(test, "TSHttpHdrPrint", "TestCase1", TC_FAIL, "Unable to allocate memory");
4616       } else {
4617         TSIOBufferBlock iobufblock;
4618         int64_t bytes_read;
4619 
4620         memset(actual_iobuf, 0, (actual_length + 1) * sizeof(char));
4621         bytes_read = 0;
4622 
4623         iobufblock = TSIOBufferReaderStart(iobufreader);
4624 
4625         while (iobufblock != nullptr) {
4626           const char *block_start;
4627           int64_t block_size;
4628 
4629           block_start = TSIOBufferBlockReadStart(iobufblock, iobufreader, &block_size);
4630           if (block_size <= 0) {
4631             break;
4632           }
4633 
4634           memcpy(actual_iobuf + bytes_read, block_start, block_size);
4635           bytes_read += block_size;
4636           TSIOBufferReaderConsume(iobufreader, block_size);
4637           iobufblock = TSIOBufferReaderStart(iobufreader);
4638         }
4639         if (strcmp(actual_iobuf, expected_iobuf) == 0) {
4640           SDK_RPRINT(test, "TSHttpHdrPrint", "TestCase1", TC_PASS, "ok");
4641           test_passed_Http_Hdr_Print = true;
4642         } else {
4643           SDK_RPRINT(test, "TSHttpHdrPrint", "TestCase1", TC_FAIL, "Value's mismatch");
4644         }
4645 
4646         TSfree(actual_iobuf);
4647         TSIOBufferReaderFree(iobufreader);
4648         TSIOBufferDestroy(iobuf);
4649       }
4650     } else {
4651       SDK_RPRINT(test, "TSHttpHdrPrint", "TestCase1", TC_FAIL, "Unable to run test for TSHttpHdrPrint");
4652     }
4653   } else {
4654     SDK_RPRINT(test, "TSHttpHdrLengthGet", "All Test Cases", TC_PASS, "Cannot run test as TSHttpHdrCreate has failed");
4655   }
4656 
4657   // Destroy
4658   if (test_passed_Http_Hdr_Create == true) {
4659     TSHttpHdrDestroy(bufp1, hdr_loc1);
4660     TSHttpHdrDestroy(bufp2, hdr_loc2);
4661     TSHttpHdrDestroy(bufp3, hdr_loc3);
4662     TSHttpHdrDestroy(bufp4, hdr_loc4);
4663     if ((TSHandleMLocRelease(bufp1, TS_NULL_MLOC, hdr_loc1) == TS_ERROR) ||
4664         (TSHandleMLocRelease(bufp2, TS_NULL_MLOC, hdr_loc2) == TS_ERROR) ||
4665         (TSHandleMLocRelease(bufp3, TS_NULL_MLOC, hdr_loc3) == TS_ERROR) ||
4666         (TSHandleMLocRelease(bufp4, TS_NULL_MLOC, hdr_loc4) == TS_ERROR)) {
4667       SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase1|2|3|4", TC_FAIL, "Unable to release the handle to headers");
4668     }
4669     SDK_RPRINT(test, "TSHttpHdrDestroy", "TestCase1&2&3&4", TC_PASS, "ok");
4670     test_passed_Http_Hdr_Destroy = true;
4671   } else {
4672     SDK_RPRINT(test, "TSHttpHdrDestroy", "All Test Cases", TC_FAIL, "Cannot run test as header was not created");
4673   }
4674 
4675   if (bufp1) {
4676     if (TSMBufferDestroy(bufp1) == TS_ERROR) {
4677       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase1", TC_FAIL, "Unable to destroy MBuffer");
4678     }
4679   }
4680 
4681   if (bufp2) {
4682     if (TSMBufferDestroy(bufp2) == TS_ERROR) {
4683       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase2", TC_FAIL, "Unable to destroy MBuffer");
4684     }
4685   }
4686 
4687   if (bufp3) {
4688     if (TSMBufferDestroy(bufp3) == TS_ERROR) {
4689       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase3", TC_FAIL, "Unable to destroy MBuffer");
4690     }
4691   }
4692 
4693   if (bufp4) {
4694     if (TSMBufferDestroy(bufp4) == TS_ERROR) {
4695       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase4", TC_FAIL, "Unable to destroy MBuffer");
4696     }
4697   }
4698 
4699   if ((test_passed_Http_Hdr_Create == true) && (test_passed_Http_Hdr_Type == true) && (test_passed_Http_Hdr_Method == true) &&
4700       (test_passed_Http_Hdr_Url == true) && (test_passed_Http_Hdr_Status == true) && (test_passed_Http_Hdr_Reason == true) &&
4701       (test_passed_Http_Hdr_Reason_Lookup == true) && (test_passed_Http_Hdr_Version == true) &&
4702       (test_passed_Http_Hdr_Copy == true) && (test_passed_Http_Hdr_Clone == true) && (test_passed_Http_Hdr_Length == true) &&
4703       (test_passed_Http_Hdr_Print == true) && (test_passed_Http_Hdr_Destroy == true)) {
4704     *pstatus = REGRESSION_TEST_PASSED;
4705   } else {
4706     *pstatus = REGRESSION_TEST_FAILED;
4707   }
4708 
4709   return;
4710 }
4711 
4712 //////////////////////////////////////////////
4713 //       SDK_API_TSMimeHdrField
4714 //
4715 // Unit Test for API: TSMBufferCreate
4716 //                    TSMBufferDestroy
4717 //                    TSMimeHdrCreate
4718 //                    TSMimeHdrDestroy
4719 //                    TSMimeHdrFieldCreate
4720 //                    TSMimeHdrFieldDestroy
4721 //                    TSMimeHdrFieldFind
4722 //                    TSMimeHdrFieldGet
4723 //                    TSMimeHdrFieldAppend
4724 //                    TSMimeHdrFieldNameGet
4725 //                    TSMimeHdrFieldNameSet
4726 //                    TSMimeHdrFieldNext
4727 //                    TSMimeHdrFieldsClear
4728 //                    TSMimeHdrFieldsCount
4729 //                    TSMimeHdrFieldValueAppend
4730 //                    TSMimeHdrFieldValueDelete
4731 //                    TSMimeHdrFieldValueStringGet
4732 //                    TSMimeHdrFieldValueDateGet
4733 //                    TSMimeHdrFieldValueIntGet
4734 //                    TSMimeHdrFieldValueUintGet
4735 //                    TSMimeHdrFieldValueStringInsert
4736 //                    TSMimeHdrFieldValueDateInsert
4737 //                    TSMimeHdrFieldValueIntInsert
4738 //                    TSMimeHdrFieldValueUintInsert
4739 //                    TSMimeHdrFieldValuesClear
4740 //                    TSMimeHdrFieldValuesCount
4741 //                    TSMimeHdrFieldValueStringSet
4742 //                    TSMimeHdrFieldValueDateSet
4743 //                    TSMimeHdrFieldValueIntSet
4744 //                    TSMimeHdrFieldValueUintSet
4745 //                    TSMimeHdrLengthGet
4746 //                    TSMimeHdrPrint
4747 //////////////////////////////////////////////
4748 
4749 TSReturnCode
compare_field_names(RegressionTest *,TSMBuffer bufp1,TSMLoc mime_loc1,TSMLoc field_loc1,TSMBuffer bufp2,TSMLoc mime_loc2,TSMLoc field_loc2)4750 compare_field_names(RegressionTest * /* test ATS_UNUSED */, TSMBuffer bufp1, TSMLoc mime_loc1, TSMLoc field_loc1, TSMBuffer bufp2,
4751                     TSMLoc mime_loc2, TSMLoc field_loc2)
4752 {
4753   const char *name1;
4754   const char *name2;
4755   int length1;
4756   int length2;
4757 
4758   name1 = TSMimeHdrFieldNameGet(bufp1, mime_loc1, field_loc1, &length1);
4759   name2 = TSMimeHdrFieldNameGet(bufp2, mime_loc2, field_loc2, &length2);
4760 
4761   if ((length1 == length2) && (strncmp(name1, name2, length1) == 0)) {
4762     return TS_SUCCESS;
4763   } else {
4764     return TS_ERROR;
4765   }
4766 }
4767 
REGRESSION_TEST(SDK_API_TSMimeHdrField)4768 REGRESSION_TEST(SDK_API_TSMimeHdrField)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
4769 {
4770   TSMBuffer bufp1 = (TSMBuffer) nullptr;
4771 
4772   TSMLoc mime_loc1 = (TSMLoc) nullptr;
4773 
4774   TSMLoc field_loc11 = (TSMLoc) nullptr;
4775   TSMLoc field_loc12 = (TSMLoc) nullptr;
4776   TSMLoc field_loc13 = (TSMLoc) nullptr;
4777   TSMLoc field_loc14 = (TSMLoc) nullptr;
4778   TSMLoc field_loc15 = (TSMLoc) nullptr;
4779 
4780   const char *field1Name = "field1";
4781   const char *field2Name = "field2";
4782   const char *field3Name = "field3";
4783   const char *field4Name = "field4";
4784   const char *field5Name = "field5";
4785 
4786   const char *field1NameGet;
4787   const char *field2NameGet;
4788   const char *field3NameGet;
4789   const char *field4NameGet;
4790   const char *field5NameGet;
4791 
4792   int field1NameGetLength;
4793   int field2NameGetLength;
4794   int field3NameGetLength;
4795   int field4NameGetLength;
4796   int field5NameGetLength;
4797 
4798   int field1_length;
4799   int field2_length;
4800   int field3_length;
4801   int field4_length;
4802   /* int field5_length; unused: lv */
4803 
4804   TSMLoc test_field_loc11 = (TSMLoc) nullptr;
4805   TSMLoc test_field_loc12 = (TSMLoc) nullptr;
4806   TSMLoc test_field_loc13 = (TSMLoc) nullptr;
4807   TSMLoc test_field_loc14 = (TSMLoc) nullptr;
4808   TSMLoc test_field_loc15 = (TSMLoc) nullptr;
4809 
4810   int actualNumberOfFields;
4811   int numberOfFields;
4812 
4813   const char *field1Value1   = "field1Value1";
4814   const char *field1Value2   = "field1Value2";
4815   const char *field1Value3   = "field1Value3";
4816   const char *field1Value4   = "field1Value4";
4817   const char *field1Value5   = "field1Value5";
4818   const char *field1ValueNew = "newfieldValue";
4819 
4820   const char *field1Value1Get;
4821   const char *field1Value2Get;
4822   const char *field1Value3Get;
4823   const char *field1Value4Get;
4824   const char *field1Value5Get;
4825   const char *field1ValueAllGet;
4826   const char *field1ValueNewGet;
4827 
4828   int lengthField1Value1;
4829   int lengthField1Value2;
4830   int lengthField1Value3;
4831   int lengthField1Value4;
4832   int lengthField1Value5;
4833   int lengthField1ValueAll;
4834   int lengthField1ValueNew;
4835 
4836   time_t field2Value1 = time(nullptr);
4837   time_t field2Value1Get;
4838   time_t field2ValueNew;
4839   time_t field2ValueNewGet;
4840 
4841   int field3Value1   = 31;
4842   int field3Value2   = 32;
4843   int field3Value3   = 33;
4844   int field3Value4   = 34;
4845   int field3Value5   = 35;
4846   int field3ValueNew = 30;
4847 
4848   int field3Value1Get;
4849   int field3Value2Get;
4850   int field3Value3Get;
4851   int field3Value4Get;
4852   int field3Value5Get;
4853   int field3ValueNewGet;
4854 
4855   unsigned int field4Value1   = 41;
4856   unsigned int field4Value2   = 42;
4857   unsigned int field4Value3   = 43;
4858   unsigned int field4Value4   = 44;
4859   unsigned int field4Value5   = 45;
4860   unsigned int field4ValueNew = 40;
4861 
4862   unsigned int field4Value1Get;
4863   unsigned int field4Value2Get;
4864   unsigned int field4Value3Get;
4865   unsigned int field4Value4Get;
4866   unsigned int field4Value5Get;
4867   unsigned int field4ValueNewGet;
4868 
4869   const char *field5Value1       = "field5Value1";
4870   const char *field5Value1Append = "AppendedValue";
4871   const char *fieldValueAppendGet;
4872   int lengthFieldValueAppended;
4873   int field5Value2         = 52;
4874   const char *field5Value3 = "DeleteValue";
4875   const char *fieldValueDeleteGet;
4876   int lengthFieldValueDeleteGet;
4877   unsigned int field5Value4 = 54;
4878   int numberOfValueInField;
4879 
4880   TSMLoc field_loc;
4881 
4882   bool test_passed_MBuffer_Create                     = false;
4883   bool test_passed_Mime_Hdr_Create                    = false;
4884   bool test_passed_Mime_Hdr_Field_Create              = false;
4885   bool test_passed_Mime_Hdr_Field_Name                = false;
4886   bool test_passed_Mime_Hdr_Field_Append              = false;
4887   bool test_passed_Mime_Hdr_Field_Get                 = false;
4888   bool test_passed_Mime_Hdr_Field_Next                = false;
4889   bool test_passed_Mime_Hdr_Fields_Count              = false;
4890   bool test_passed_Mime_Hdr_Field_Value_String_Insert = false;
4891   bool test_passed_Mime_Hdr_Field_Value_String_Get    = false;
4892   bool test_passed_Mime_Hdr_Field_Value_String_Set    = false;
4893   bool test_passed_Mime_Hdr_Field_Value_Date_Insert   = false;
4894   bool test_passed_Mime_Hdr_Field_Value_Date_Get      = false;
4895   bool test_passed_Mime_Hdr_Field_Value_Date_Set      = false;
4896   bool test_passed_Mime_Hdr_Field_Value_Int_Insert    = false;
4897   bool test_passed_Mime_Hdr_Field_Value_Int_Get       = false;
4898   bool test_passed_Mime_Hdr_Field_Value_Int_Set       = false;
4899   bool test_passed_Mime_Hdr_Field_Value_Uint_Insert   = false;
4900   bool test_passed_Mime_Hdr_Field_Value_Uint_Get      = false;
4901   bool test_passed_Mime_Hdr_Field_Value_Uint_Set      = false;
4902   bool test_passed_Mime_Hdr_Field_Value_Append        = false;
4903   bool test_passed_Mime_Hdr_Field_Value_Delete        = false;
4904   bool test_passed_Mime_Hdr_Field_Values_Clear        = false;
4905   bool test_passed_Mime_Hdr_Field_Values_Count        = false;
4906   bool test_passed_Mime_Hdr_Field_Destroy             = false;
4907   bool test_passed_Mime_Hdr_Fields_Clear              = false;
4908   bool test_passed_Mime_Hdr_Destroy                   = false;
4909   bool test_passed_MBuffer_Destroy                    = false;
4910   bool test_passed_Mime_Hdr_Field_Length_Get          = false;
4911 
4912   *pstatus = REGRESSION_TEST_INPROGRESS;
4913 
4914   // TSMBufferCreate
4915   bufp1 = TSMBufferCreate();
4916   SDK_RPRINT(test, "TSMBufferCreate", "TestCase1", TC_PASS, "ok");
4917   test_passed_MBuffer_Create = true;
4918 
4919   // TSMimeHdrCreate
4920   if (test_passed_MBuffer_Create == true) {
4921     if (TSMimeHdrCreate(bufp1, &mime_loc1) != TS_SUCCESS) {
4922       SDK_RPRINT(test, "TSMimeHdrCreate", "TestCase1", TC_FAIL, "TSMimeHdrCreate Returns TS_ERROR");
4923     } else {
4924       SDK_RPRINT(test, "TSMimeHdrCreate", "TestCase1", TC_PASS, "ok");
4925       test_passed_Mime_Hdr_Create = true;
4926     }
4927   } else {
4928     SDK_RPRINT(test, "TSMimeHdrCreate", "TestCase1", TC_FAIL, "Cannot run test as Test for TSMBufferCreate Failed");
4929   }
4930 
4931   // TSMimeHdrFieldCreate
4932   if (test_passed_Mime_Hdr_Create == true) {
4933     if ((TSMimeHdrFieldCreate(bufp1, mime_loc1, &field_loc11) != TS_SUCCESS) ||
4934         (TSMimeHdrFieldCreate(bufp1, mime_loc1, &field_loc12) != TS_SUCCESS) ||
4935         (TSMimeHdrFieldCreate(bufp1, mime_loc1, &field_loc13) != TS_SUCCESS) ||
4936         (TSMimeHdrFieldCreate(bufp1, mime_loc1, &field_loc14) != TS_SUCCESS) ||
4937         (TSMimeHdrFieldCreate(bufp1, mime_loc1, &field_loc15) != TS_SUCCESS)) {
4938       SDK_RPRINT(test, "TSMimeHdrFieldCreate", "TestCase1|2|3|4|5", TC_FAIL, "TSMimeHdrFieldCreate Returns TS_ERROR");
4939     } else {
4940       SDK_RPRINT(test, "TSMimeHdrFieldCreate", "TestCase1|2|3|4|5", TC_PASS, "ok");
4941       test_passed_Mime_Hdr_Field_Create = true;
4942     }
4943   } else {
4944     SDK_RPRINT(test, "TSMimeHdrFieldCreate", "All Test Case", TC_FAIL, "Cannot run test as Test for TSMimeHdrCreate Failed");
4945   }
4946 
4947   // TSMimeHdrFieldNameGet&Set
4948   if (test_passed_Mime_Hdr_Field_Create == true) {
4949     if ((TSMimeHdrFieldNameSet(bufp1, mime_loc1, field_loc11, field1Name, -1) == TS_ERROR) ||
4950         (TSMimeHdrFieldNameSet(bufp1, mime_loc1, field_loc12, field2Name, -1) == TS_ERROR) ||
4951         (TSMimeHdrFieldNameSet(bufp1, mime_loc1, field_loc13, field3Name, -1) == TS_ERROR) ||
4952         (TSMimeHdrFieldNameSet(bufp1, mime_loc1, field_loc14, field4Name, -1) == TS_ERROR) ||
4953         (TSMimeHdrFieldNameSet(bufp1, mime_loc1, field_loc15, field5Name, -1) == TS_ERROR)) {
4954       SDK_RPRINT(test, "TSMimeHdrFieldNameSet", "TestCase1|2|3|4|5", TC_FAIL, "TSMimeHdrFieldNameSet Returns TS_ERROR");
4955     } else {
4956       field1NameGet = TSMimeHdrFieldNameGet(bufp1, mime_loc1, field_loc11, &field1NameGetLength);
4957       field2NameGet = TSMimeHdrFieldNameGet(bufp1, mime_loc1, field_loc12, &field2NameGetLength);
4958       field3NameGet = TSMimeHdrFieldNameGet(bufp1, mime_loc1, field_loc13, &field3NameGetLength);
4959       field4NameGet = TSMimeHdrFieldNameGet(bufp1, mime_loc1, field_loc14, &field4NameGetLength);
4960       field5NameGet = TSMimeHdrFieldNameGet(bufp1, mime_loc1, field_loc15, &field5NameGetLength);
4961       if (((strncmp(field1NameGet, field1Name, field1NameGetLength) == 0) &&
4962            (field1NameGetLength == static_cast<int>(strlen(field1Name)))) &&
4963           ((strncmp(field2NameGet, field2Name, field2NameGetLength) == 0) &&
4964            (field2NameGetLength == static_cast<int>(strlen(field2Name)))) &&
4965           ((strncmp(field3NameGet, field3Name, field3NameGetLength) == 0) &&
4966            (field3NameGetLength == static_cast<int>(strlen(field3Name)))) &&
4967           ((strncmp(field4NameGet, field4Name, field4NameGetLength) == 0) &&
4968            (field4NameGetLength == static_cast<int>(strlen(field4Name)))) &&
4969           ((strncmp(field5NameGet, field5Name, field5NameGetLength) == 0) &&
4970            field5NameGetLength == static_cast<int>(strlen(field5Name)))) {
4971         SDK_RPRINT(test, "TSMimeHdrFieldNameGet&Set", "TestCase1&2&3&4&5", TC_PASS, "ok");
4972         test_passed_Mime_Hdr_Field_Name = true;
4973       } else {
4974         SDK_RPRINT(test, "TSMimeHdrFieldNameGet&Set", "TestCase1|2|3|4|5", TC_FAIL, "Values Don't Match");
4975       }
4976     }
4977   } else {
4978     SDK_RPRINT(test, "TSMimeHdrFieldNameGet&Set", "All Test Case", TC_FAIL,
4979                "Cannot run test as Test for TSMBufferFieldCreate Failed");
4980   }
4981 
4982   // TSMimeHdrFieldAppend, TSMimeHdrFieldGet, TSMimeHdrFieldNext
4983   if (test_passed_Mime_Hdr_Field_Name == true) {
4984     if ((TSMimeHdrFieldAppend(bufp1, mime_loc1, field_loc11) != TS_SUCCESS) ||
4985         (TSMimeHdrFieldAppend(bufp1, mime_loc1, field_loc12) != TS_SUCCESS) ||
4986         (TSMimeHdrFieldAppend(bufp1, mime_loc1, field_loc13) != TS_SUCCESS) ||
4987         (TSMimeHdrFieldAppend(bufp1, mime_loc1, field_loc14) != TS_SUCCESS) ||
4988         (TSMimeHdrFieldAppend(bufp1, mime_loc1, field_loc15) != TS_SUCCESS)) {
4989       SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase1|2|3|4|5", TC_FAIL, "TSMimeHdrFieldAppend Returns TS_ERROR");
4990     } else {
4991       if (TS_NULL_MLOC == (test_field_loc11 = TSMimeHdrFieldGet(bufp1, mime_loc1, 0))) {
4992         SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase1|2|3|4|5", TC_FAIL, "TSMimeHdrFieldGet Returns TS_NULL_MLOC");
4993         SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase1", TC_FAIL,
4994                    "Cannot Test TSMimeHdrFieldNext as TSMimeHdrFieldGet Returns TS_NULL_MLOC");
4995         SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase1", TC_FAIL, "TSMimeHdrFieldGet Returns TS_NULL_MLOC");
4996       } else {
4997         if (compare_field_names(test, bufp1, mime_loc1, field_loc11, bufp1, mime_loc1, test_field_loc11) == TS_ERROR) {
4998           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase1", TC_FAIL, "Values Don't match");
4999           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase1", TC_FAIL, "Cannot Test TSMimeHdrFieldNext as Values don't match");
5000           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase1", TC_FAIL, "Values Don't match");
5001         } else {
5002           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase1", TC_PASS, "ok");
5003           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase1", TC_PASS, "ok");
5004           test_passed_Mime_Hdr_Field_Append = true;
5005           test_passed_Mime_Hdr_Field_Get    = true;
5006         }
5007       }
5008 
5009       if (test_passed_Mime_Hdr_Field_Append == true) {
5010         test_field_loc12 = TSMimeHdrFieldNext(bufp1, mime_loc1, test_field_loc11);
5011         if (compare_field_names(test, bufp1, mime_loc1, field_loc12, bufp1, mime_loc1, test_field_loc12) == TS_ERROR) {
5012           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase2", TC_PASS, "Values Don't match");
5013           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase2", TC_PASS, "Values Don't match");
5014           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase2", TC_PASS, "Values Don't match");
5015           test_passed_Mime_Hdr_Field_Append = false;
5016           test_passed_Mime_Hdr_Field_Next   = false;
5017           test_passed_Mime_Hdr_Field_Get    = false;
5018         } else {
5019           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase2", TC_PASS, "ok");
5020           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase2", TC_PASS, "ok");
5021           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase2", TC_PASS, "ok");
5022           test_passed_Mime_Hdr_Field_Next = true;
5023         }
5024       }
5025 
5026       if (test_passed_Mime_Hdr_Field_Append == true) {
5027         test_field_loc13 = TSMimeHdrFieldNext(bufp1, mime_loc1, test_field_loc12);
5028         if (compare_field_names(test, bufp1, mime_loc1, field_loc13, bufp1, mime_loc1, test_field_loc13) == TS_ERROR) {
5029           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase3", TC_FAIL, "Values Don't match");
5030           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase3", TC_FAIL, "Values Don't match");
5031           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase3", TC_FAIL, "Values Don't match");
5032           test_passed_Mime_Hdr_Field_Append = false;
5033           test_passed_Mime_Hdr_Field_Next   = false;
5034           test_passed_Mime_Hdr_Field_Get    = false;
5035         } else {
5036           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase3", TC_PASS, "ok");
5037           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase3", TC_PASS, "ok");
5038           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase3", TC_PASS, "ok");
5039         }
5040       }
5041 
5042       if (test_passed_Mime_Hdr_Field_Append == true) {
5043         test_field_loc14 = TSMimeHdrFieldNext(bufp1, mime_loc1, test_field_loc13);
5044         if (compare_field_names(test, bufp1, mime_loc1, field_loc14, bufp1, mime_loc1, test_field_loc14) == TS_ERROR) {
5045           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase4", TC_FAIL, "Values Don't match");
5046           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase4", TC_FAIL, "Values Don't match");
5047           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase4", TC_FAIL, "Values Don't match");
5048           test_passed_Mime_Hdr_Field_Append = false;
5049           test_passed_Mime_Hdr_Field_Next   = false;
5050           test_passed_Mime_Hdr_Field_Get    = false;
5051         } else {
5052           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase4", TC_PASS, "ok");
5053           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase4", TC_PASS, "ok");
5054           SDK_RPRINT(test, "TSMimeHdrFieldGet", "TestCase4", TC_PASS, "ok");
5055         }
5056       }
5057 
5058       if (test_passed_Mime_Hdr_Field_Append == true) {
5059         test_field_loc15 = TSMimeHdrFieldNext(bufp1, mime_loc1, test_field_loc14);
5060         if (compare_field_names(test, bufp1, mime_loc1, field_loc15, bufp1, mime_loc1, test_field_loc15) == TS_ERROR) {
5061           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase5", TC_FAIL, "Values Don't match");
5062           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase5", TC_FAIL, "Values Don't match");
5063           test_passed_Mime_Hdr_Field_Append = false;
5064           test_passed_Mime_Hdr_Field_Next   = false;
5065           test_passed_Mime_Hdr_Field_Get    = false;
5066         } else {
5067           SDK_RPRINT(test, "TSMimeHdrFieldAppend", "TestCase5", TC_PASS, "ok");
5068           SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase5", TC_PASS, "ok");
5069         }
5070       }
5071 
5072       if ((TSHandleMLocRelease(bufp1, mime_loc1, test_field_loc11) == TS_ERROR) ||
5073           (TSHandleMLocRelease(bufp1, mime_loc1, test_field_loc12) == TS_ERROR) ||
5074           (TSHandleMLocRelease(bufp1, mime_loc1, test_field_loc13) == TS_ERROR) ||
5075           (TSHandleMLocRelease(bufp1, mime_loc1, test_field_loc14) == TS_ERROR) ||
5076           (TSHandleMLocRelease(bufp1, mime_loc1, test_field_loc15) == TS_ERROR)) {
5077         SDK_RPRINT(test, "TSMimeHdrFieldAppend/Next/Get", "", TC_FAIL,
5078                    "Unable to release handle using TSHandleMLocRelease. Can be bad handle.");
5079       }
5080     }
5081   } else {
5082     SDK_RPRINT(test, "TSMimeHdrFieldAppend & TSMimeHdrFieldNext", "All Test Case", TC_FAIL,
5083                "Cannot run test as Test for TSMimeHdrFieldNameGet&Set Failed");
5084   }
5085 
5086   // TSMimeHdrFieldsCount
5087   if (test_passed_Mime_Hdr_Field_Create == true) {
5088     if ((numberOfFields = TSMimeHdrFieldsCount(bufp1, mime_loc1)) < 0) {
5089       SDK_RPRINT(test, "TSMimeHdrFieldsCount", "TestCase1", TC_FAIL, "TSMimeHdrFieldsCount Returns TS_ERROR");
5090     } else {
5091       actualNumberOfFields = 0;
5092       if ((field_loc = TSMimeHdrFieldGet(bufp1, mime_loc1, actualNumberOfFields)) == TS_NULL_MLOC) {
5093         SDK_RPRINT(test, "TSMimeHdrFieldsCount", "TestCase1", TC_FAIL, "TSMimeHdrFieldGet Returns TS_NULL_MLOC");
5094       } else {
5095         while (field_loc != nullptr) {
5096           TSMLoc next_field_loc;
5097 
5098           actualNumberOfFields++;
5099           next_field_loc = TSMimeHdrFieldNext(bufp1, mime_loc1, field_loc);
5100           if (TSHandleMLocRelease(bufp1, mime_loc1, field_loc) == TS_ERROR) {
5101             SDK_RPRINT(test, "TSMimeHdrFieldsCount", "TestCase1", TC_FAIL, "Unable to release handle using TSHandleMLocRelease");
5102           }
5103           field_loc      = next_field_loc;
5104           next_field_loc = nullptr;
5105         }
5106         if (actualNumberOfFields == numberOfFields) {
5107           SDK_RPRINT(test, "TSMimeHdrFieldsCount", "TestCase1", TC_PASS, "ok");
5108           test_passed_Mime_Hdr_Fields_Count = true;
5109         } else {
5110           SDK_RPRINT(test, "TSMimeHdrFieldsCount", "TestCase1", TC_FAIL, "Values don't match");
5111         }
5112       }
5113     }
5114   } else {
5115     SDK_RPRINT(test, "TSMimeHdrFieldsCount", "TestCase1", TC_FAIL, "Cannot run Test as TSMimeHdrFieldCreate failed");
5116   }
5117 
5118   // TSMimeHdrFieldValueStringInsert, TSMimeHdrFieldValueStringGet, TSMimeHdrFieldValueStringSet
5119   if (test_passed_Mime_Hdr_Field_Create == true) {
5120     if ((TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc11, -1, field1Value2, -1) == TS_ERROR) ||
5121         (TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc11, 0, field1Value1, -1) == TS_ERROR) ||
5122         (TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc11, -1, field1Value5, -1) == TS_ERROR) ||
5123         (TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc11, 2, field1Value4, -1) == TS_ERROR) ||
5124         (TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc11, 2, field1Value3, -1) == TS_ERROR)) {
5125       SDK_RPRINT(test, "TSMimeHdrFieldValueStringInsert", "TestCase1|2|3|4|5", TC_FAIL,
5126                  "TSMimeHdrFieldValueStringInsert Returns TS_ERROR");
5127       SDK_RPRINT(test, "TSMimeHdrFieldValueStringGet", "TestCase1&2&3&4&5", TC_FAIL,
5128                  "Cannot run Test as TSMimeHdrFieldValueStringInsert returns TS_ERROR");
5129       SDK_RPRINT(test, "TSMimeHdrFieldValueStringSet", "TestCase1", TC_FAIL,
5130                  "Cannot run Test as TSMimeHdrFieldValueStringInsert returns TS_ERROR");
5131     } else {
5132       field1Value1Get   = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, 0, &lengthField1Value1);
5133       field1Value2Get   = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, 1, &lengthField1Value2);
5134       field1Value3Get   = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, 2, &lengthField1Value3);
5135       field1Value4Get   = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, 3, &lengthField1Value4);
5136       field1Value5Get   = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, 4, &lengthField1Value5);
5137       field1ValueAllGet = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, -1, &lengthField1ValueAll);
5138       if (((strncmp(field1Value1Get, field1Value1, lengthField1Value1) == 0) &&
5139            lengthField1Value1 == static_cast<int>(strlen(field1Value1))) &&
5140           ((strncmp(field1Value2Get, field1Value2, lengthField1Value2) == 0) &&
5141            lengthField1Value2 == static_cast<int>(strlen(field1Value2))) &&
5142           ((strncmp(field1Value3Get, field1Value3, lengthField1Value3) == 0) &&
5143            lengthField1Value3 == static_cast<int>(strlen(field1Value3))) &&
5144           ((strncmp(field1Value4Get, field1Value4, lengthField1Value4) == 0) &&
5145            lengthField1Value4 == static_cast<int>(strlen(field1Value4))) &&
5146           ((strncmp(field1Value5Get, field1Value5, lengthField1Value5) == 0) &&
5147            lengthField1Value5 == static_cast<int>(strlen(field1Value5))) &&
5148           (strstr(field1ValueAllGet, field1Value1Get) == field1Value1Get) &&
5149           (strstr(field1ValueAllGet, field1Value2Get) == field1Value2Get) &&
5150           (strstr(field1ValueAllGet, field1Value3Get) == field1Value3Get) &&
5151           (strstr(field1ValueAllGet, field1Value4Get) == field1Value4Get) &&
5152           (strstr(field1ValueAllGet, field1Value5Get) == field1Value5Get)) {
5153         SDK_RPRINT(test, "TSMimeHdrFieldValueStringInsert", "TestCase1&2&3&4&5", TC_PASS, "ok");
5154         SDK_RPRINT(test, "TSMimeHdrFieldValueStringGet", "TestCase1&2&3&4&5", TC_PASS, "ok");
5155         SDK_RPRINT(test, "TSMimeHdrFieldValueStringGet with IDX=-1", "TestCase1&2&3&4&5", TC_PASS, "ok");
5156         test_passed_Mime_Hdr_Field_Value_String_Insert = true;
5157         test_passed_Mime_Hdr_Field_Value_String_Get    = true;
5158 
5159         if ((TSMimeHdrFieldValueStringSet(bufp1, mime_loc1, field_loc11, 3, field1ValueNew, -1)) == TS_ERROR) {
5160           SDK_RPRINT(test, "TSMimeHdrFieldValueStringSet", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueStringSet returns TS_ERROR");
5161         } else {
5162           field1ValueNewGet = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc11, 3, &lengthField1ValueNew);
5163           if ((strncmp(field1ValueNewGet, field1ValueNew, lengthField1ValueNew) == 0) &&
5164               (lengthField1ValueNew == static_cast<int>(strlen(field1ValueNew)))) {
5165             SDK_RPRINT(test, "TSMimeHdrFieldValueStringSet", "TestCase1", TC_PASS, "ok");
5166             test_passed_Mime_Hdr_Field_Value_String_Set = true;
5167           } else {
5168             SDK_RPRINT(test, "TSMimeHdrFieldValueStringSet", "TestCase1", TC_FAIL, "Value's Don't match");
5169           }
5170         }
5171       } else {
5172         SDK_RPRINT(test, "TSMimeHdrFieldValueStringInsert", "TestCase1|2|3|4|5", TC_PASS, "Value's Don't Match");
5173         SDK_RPRINT(test, "TSMimeHdrFieldValueStringGet", "TestCase1|2|3|4|5", TC_PASS, "Value's Don't Match");
5174         SDK_RPRINT(test, "TSMimeHdrFieldValueStringSet", "TestCase1", TC_FAIL,
5175                    "TSMimeHdrFieldValueStringSet cannot be tested as TSMimeHdrFieldValueStringInsert|Get failed");
5176       }
5177     }
5178   } else {
5179     SDK_RPRINT(test, "TSMimeHdrFieldValueStringInsert&Set&Get", "All", TC_FAIL, "Cannot run Test as TSMimeHdrFieldCreate failed");
5180   }
5181 
5182   // TSMimeHdrFieldValueDateInsert, TSMimeHdrFieldValueDateGet, TSMimeHdrFieldValueDateSet
5183   if (test_passed_Mime_Hdr_Field_Create == true) {
5184     if (TSMimeHdrFieldValueDateInsert(bufp1, mime_loc1, field_loc12, field2Value1) == TS_ERROR) {
5185       SDK_RPRINT(test, "TSMimeHdrFieldValueDateInsert", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueDateInsert Returns TS_ERROR");
5186       SDK_RPRINT(test, "TSMimeHdrFieldValueDateGet", "TestCase1", TC_FAIL,
5187                  "Cannot run Test as TSMimeHdrFieldValueDateInsert returns TS_ERROR");
5188       SDK_RPRINT(test, "TSMimeHdrFieldValueDateSet", "TestCase1", TC_FAIL,
5189                  "Cannot run Test as TSMimeHdrFieldValueDateInsert returns TS_ERROR");
5190     } else {
5191       field2Value1Get = TSMimeHdrFieldValueDateGet(bufp1, mime_loc1, field_loc12);
5192       if (field2Value1Get == field2Value1) {
5193         SDK_RPRINT(test, "TSMimeHdrFieldValueDateInsert", "TestCase1", TC_PASS, "ok");
5194         SDK_RPRINT(test, "TSMimeHdrFieldValueDateGet", "TestCase1", TC_PASS, "ok");
5195         test_passed_Mime_Hdr_Field_Value_Date_Insert = true;
5196         test_passed_Mime_Hdr_Field_Value_Date_Get    = true;
5197         field2ValueNew                               = time(nullptr);
5198         if ((TSMimeHdrFieldValueDateSet(bufp1, mime_loc1, field_loc12, field2ValueNew)) == TS_ERROR) {
5199           SDK_RPRINT(test, "TSMimeHdrFieldValueDateSet", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueDateSet returns TS_ERROR");
5200         } else {
5201           field2ValueNewGet = TSMimeHdrFieldValueDateGet(bufp1, mime_loc1, field_loc12);
5202           if (field2ValueNewGet == field2ValueNew) {
5203             SDK_RPRINT(test, "TSMimeHdrFieldValueDateSet", "TestCase1", TC_PASS, "ok");
5204             test_passed_Mime_Hdr_Field_Value_Date_Set = true;
5205           } else {
5206             SDK_RPRINT(test, "TSMimeHdrFieldValueDateSet", "TestCase1", TC_FAIL, "Value's Don't match");
5207           }
5208         }
5209       } else {
5210         SDK_RPRINT(test, "TSMimeHdrFieldValueDateInsert", "TestCase1", TC_PASS, "Value's Don't Match");
5211         SDK_RPRINT(test, "TSMimeHdrFieldValueDateGet", "TestCase1", TC_PASS, "Value's Don't Match");
5212         SDK_RPRINT(test, "TSMimeHdrFieldValueDateSet", "TestCase1", TC_FAIL,
5213                    "TSMimeHdrFieldValueDateSet cannot be tested as TSMimeHdrFieldValueDateInsert|Get failed");
5214       }
5215     }
5216   } else {
5217     SDK_RPRINT(test, "TSMimeHdrFieldValueDateInsert&Set&Get", "TestCase1", TC_FAIL,
5218                "Cannot run Test as TSMimeHdrFieldCreate failed");
5219   }
5220 
5221   // TSMimeHdrFieldValueIntInsert, TSMimeHdrFieldValueIntGet, TSMimeHdrFieldValueIntSet
5222   if (test_passed_Mime_Hdr_Field_Create == true) {
5223     if ((TSMimeHdrFieldValueIntInsert(bufp1, mime_loc1, field_loc13, -1, field3Value2) == TS_ERROR) ||
5224         (TSMimeHdrFieldValueIntInsert(bufp1, mime_loc1, field_loc13, 0, field3Value1) == TS_ERROR) ||
5225         (TSMimeHdrFieldValueIntInsert(bufp1, mime_loc1, field_loc13, -1, field3Value5) == TS_ERROR) ||
5226         (TSMimeHdrFieldValueIntInsert(bufp1, mime_loc1, field_loc13, 2, field3Value4) == TS_ERROR) ||
5227         (TSMimeHdrFieldValueIntInsert(bufp1, mime_loc1, field_loc13, 2, field3Value3) == TS_ERROR)) {
5228       SDK_RPRINT(test, "TSMimeHdrFieldValueIntInsert", "TestCase1|2|3|4|5", TC_FAIL,
5229                  "TSMimeHdrFieldValueIntInsert Returns TS_ERROR");
5230       SDK_RPRINT(test, "TSMimeHdrFieldValueIntGet", "TestCase1&2&3&4&5", TC_FAIL,
5231                  "Cannot run Test as TSMimeHdrFieldValueIntInsert returns TS_ERROR");
5232       SDK_RPRINT(test, "TSMimeHdrFieldValueIntSet", "TestCase1", TC_FAIL,
5233                  "Cannot run Test as TSMimeHdrFieldValueIntInsert returns TS_ERROR");
5234     } else {
5235       field3Value1Get = TSMimeHdrFieldValueIntGet(bufp1, mime_loc1, field_loc13, 0);
5236       field3Value2Get = TSMimeHdrFieldValueIntGet(bufp1, mime_loc1, field_loc13, 1);
5237       field3Value3Get = TSMimeHdrFieldValueIntGet(bufp1, mime_loc1, field_loc13, 2);
5238       field3Value4Get = TSMimeHdrFieldValueIntGet(bufp1, mime_loc1, field_loc13, 3);
5239       field3Value5Get = TSMimeHdrFieldValueIntGet(bufp1, mime_loc1, field_loc13, 4);
5240       if ((field3Value1Get == field3Value1) && (field3Value2Get == field3Value2) && (field3Value3Get == field3Value3) &&
5241           (field3Value4Get == field3Value4) && (field3Value5Get == field3Value5)) {
5242         SDK_RPRINT(test, "TSMimeHdrFieldValueIntInsert", "TestCase1&2&3&4&5", TC_PASS, "ok");
5243         SDK_RPRINT(test, "TSMimeHdrFieldValueIntGet", "TestCase1&2&3&4&5", TC_PASS, "ok");
5244         test_passed_Mime_Hdr_Field_Value_Int_Insert = true;
5245         test_passed_Mime_Hdr_Field_Value_Int_Get    = true;
5246         if ((TSMimeHdrFieldValueIntSet(bufp1, mime_loc1, field_loc13, 3, field3ValueNew)) == TS_ERROR) {
5247           SDK_RPRINT(test, "TSMimeHdrFieldValueIntSet", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueIntSet returns TS_ERROR");
5248         } else {
5249           field3ValueNewGet = TSMimeHdrFieldValueIntGet(bufp1, mime_loc1, field_loc13, 3);
5250           if (field3ValueNewGet == field3ValueNew) {
5251             SDK_RPRINT(test, "TSMimeHdrFieldValueIntSet", "TestCase1", TC_PASS, "ok");
5252             test_passed_Mime_Hdr_Field_Value_Int_Set = true;
5253           } else {
5254             SDK_RPRINT(test, "TSMimeHdrFieldValueIntSet", "TestCase1", TC_FAIL, "Value's Don't match");
5255           }
5256         }
5257       } else {
5258         SDK_RPRINT(test, "TSMimeHdrFieldValueIntInsert", "TestCase1|2|3|4|5", TC_PASS, "Value's Don't Match");
5259         SDK_RPRINT(test, "TSMimeHdrFieldValueIntGet", "TestCase1|2|3|4|5", TC_PASS, "Value's Don't Match");
5260         SDK_RPRINT(test, "TSMimeHdrFieldValueIntSet", "TestCase1", TC_FAIL,
5261                    "TSMimeHdrFieldValueIntSet cannot be tested as TSMimeHdrFieldValueIntInsert|Get failed");
5262       }
5263     }
5264   } else {
5265     SDK_RPRINT(test, "TSMimeHdrFieldValueIntInsert&Set&Get", "All", TC_FAIL, "Cannot run Test as TSMimeHdrFieldCreate failed");
5266   }
5267 
5268   // TSMimeHdrFieldValueUintInsert, TSMimeHdrFieldValueUintGet, TSMimeHdrFieldValueUintSet
5269   if (test_passed_Mime_Hdr_Field_Create == true) {
5270     if ((TSMimeHdrFieldValueUintInsert(bufp1, mime_loc1, field_loc14, -1, field4Value2) == TS_ERROR) ||
5271         (TSMimeHdrFieldValueUintInsert(bufp1, mime_loc1, field_loc14, 0, field4Value1) == TS_ERROR) ||
5272         (TSMimeHdrFieldValueUintInsert(bufp1, mime_loc1, field_loc14, -1, field4Value5) == TS_ERROR) ||
5273         (TSMimeHdrFieldValueUintInsert(bufp1, mime_loc1, field_loc14, 2, field4Value4) == TS_ERROR) ||
5274         (TSMimeHdrFieldValueUintInsert(bufp1, mime_loc1, field_loc14, 2, field4Value3) == TS_ERROR)) {
5275       SDK_RPRINT(test, "TSMimeHdrFieldValueUintInsert", "TestCase1|2|3|4|5", TC_FAIL,
5276                  "TSMimeHdrFieldValueUintInsert Returns TS_ERROR");
5277       SDK_RPRINT(test, "TSMimeHdrFieldValueUintGet", "TestCase1&2&3&4&5", TC_FAIL,
5278                  "Cannot run Test as TSMimeHdrFieldValueUintInsert returns TS_ERROR");
5279       SDK_RPRINT(test, "TSMimeHdrFieldValueUintSet", "TestCase1", TC_FAIL,
5280                  "Cannot run Test as TSMimeHdrFieldValueUintInsert returns TS_ERROR");
5281     } else {
5282       field4Value1Get = TSMimeHdrFieldValueUintGet(bufp1, mime_loc1, field_loc14, 0);
5283       field4Value2Get = TSMimeHdrFieldValueUintGet(bufp1, mime_loc1, field_loc14, 1);
5284       field4Value3Get = TSMimeHdrFieldValueUintGet(bufp1, mime_loc1, field_loc14, 2);
5285       field4Value4Get = TSMimeHdrFieldValueUintGet(bufp1, mime_loc1, field_loc14, 3);
5286       field4Value5Get = TSMimeHdrFieldValueUintGet(bufp1, mime_loc1, field_loc14, 4);
5287       if ((field4Value1Get == field4Value1) && (field4Value2Get == field4Value2) && (field4Value3Get == field4Value3) &&
5288           (field4Value4Get == field4Value4) && (field4Value5Get == field4Value5)) {
5289         SDK_RPRINT(test, "TSMimeHdrFieldValueUintInsert", "TestCase1&2&3&4&5", TC_PASS, "ok");
5290         SDK_RPRINT(test, "TSMimeHdrFieldValueUintGet", "TestCase1&2&3&4&5", TC_PASS, "ok");
5291         test_passed_Mime_Hdr_Field_Value_Uint_Insert = true;
5292         test_passed_Mime_Hdr_Field_Value_Uint_Get    = true;
5293         if ((TSMimeHdrFieldValueUintSet(bufp1, mime_loc1, field_loc14, 3, field4ValueNew)) == TS_ERROR) {
5294           SDK_RPRINT(test, "TSMimeHdrFieldValueUintSet", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueUintSet returns TS_ERROR");
5295         } else {
5296           field4ValueNewGet = TSMimeHdrFieldValueUintGet(bufp1, mime_loc1, field_loc14, 3);
5297           if (field4ValueNewGet == field4ValueNew) {
5298             SDK_RPRINT(test, "TSMimeHdrFieldValueUintSet", "TestCase1", TC_PASS, "ok");
5299             test_passed_Mime_Hdr_Field_Value_Uint_Set = true;
5300           } else {
5301             SDK_RPRINT(test, "TSMimeHdrFieldValueUintSet", "TestCase1", TC_FAIL, "Value's Don't match");
5302           }
5303         }
5304       } else {
5305         SDK_RPRINT(test, "TSMimeHdrFieldValueUintInsert", "TestCase1|2|3|4|5", TC_PASS, "Value's Don't Match");
5306         SDK_RPRINT(test, "TSMimeHdrFieldValueUintGet", "TestCase1|2|3|4|5", TC_PASS, "Value's Don't Match");
5307         SDK_RPRINT(test, "TSMimeHdrFieldValueUintSet", "TestCase1", TC_FAIL,
5308                    "TSMimeHdrFieldValueUintSet cannot be tested as TSMimeHdrFieldValueUintInsert|Get failed");
5309       }
5310     }
5311   } else {
5312     SDK_RPRINT(test, "TSMimeHdrFieldValueUintInsert&Set&Get", "All", TC_FAIL, "Cannot run Test as TSMimeHdrFieldCreate failed");
5313   }
5314 
5315   // TSMimeHdrFieldLengthGet
5316   field1_length = TSMimeHdrFieldLengthGet(bufp1, mime_loc1, field_loc11);
5317   field2_length = TSMimeHdrFieldLengthGet(bufp1, mime_loc1, field_loc12);
5318   field3_length = TSMimeHdrFieldLengthGet(bufp1, mime_loc1, field_loc13);
5319   field4_length = TSMimeHdrFieldLengthGet(bufp1, mime_loc1, field_loc14);
5320   if ((field1_length == 0) || (field2_length == 0) || (field3_length == 0) || (field4_length == 0)) {
5321     SDK_RPRINT(test, "TSMimeHdrFieldLengthGet", "TestCase1", TC_FAIL, "Returned bad length");
5322     test_passed_Mime_Hdr_Field_Length_Get = false;
5323   } else {
5324     SDK_RPRINT(test, "TSMimeHdrFieldLengthGet", "TestCase1", TC_PASS, "ok");
5325     test_passed_Mime_Hdr_Field_Length_Get = true;
5326   }
5327 
5328   // TSMimeHdrFieldValueAppend, TSMimeHdrFieldValueDelete, TSMimeHdrFieldValuesCount, TSMimeHdrFieldValuesClear
5329 
5330   if (test_passed_Mime_Hdr_Field_Create == true) {
5331     if ((TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc15, -1, field5Value1, -1) == TS_ERROR) ||
5332         (TSMimeHdrFieldValueIntInsert(bufp1, mime_loc1, field_loc15, -1, field5Value2) == TS_ERROR) ||
5333         (TSMimeHdrFieldValueStringInsert(bufp1, mime_loc1, field_loc15, -1, field5Value3, -1) == TS_ERROR) ||
5334         (TSMimeHdrFieldValueUintInsert(bufp1, mime_loc1, field_loc15, -1, field5Value4) == TS_ERROR)) {
5335       SDK_RPRINT(test, "TSMimeHdrFieldValueAppend", "TestCase1", TC_FAIL,
5336                  "TSMimeHdrFieldValueString|Int|UintInsert returns TS_ERROR. Cannot create field for testing.");
5337       SDK_RPRINT(test, "TSMimeHdrFieldValueDelete", "TestCase1", TC_FAIL,
5338                  "TSMimeHdrFieldValueString|Int|UintInsert returns TS_ERROR. Cannot create field for testing.");
5339       SDK_RPRINT(test, "TSMimeHdrFieldValuesCount", "TestCase1", TC_FAIL,
5340                  "TSMimeHdrFieldValueString|Int|UintInsert returns TS_ERROR. Cannot create field for testing.");
5341       SDK_RPRINT(test, "TSMimeHdrFieldValuesClear", "TestCase1", TC_FAIL,
5342                  "TSMimeHdrFieldValueString|Int|UintInsert returns TS_ERROR. Cannot create field for testing.");
5343     } else {
5344       if (TSMimeHdrFieldValueAppend(bufp1, mime_loc1, field_loc15, 0, field5Value1Append, -1) == TS_ERROR) {
5345         SDK_RPRINT(test, "TSMimeHdrFieldValueAppend", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueAppend returns TS_ERROR");
5346       } else {
5347         fieldValueAppendGet = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc15, 0, &lengthFieldValueAppended);
5348         char *expected_value;
5349         size_t len     = strlen(field5Value1) + strlen(field5Value1Append) + 1;
5350         expected_value = static_cast<char *>(TSmalloc(len));
5351         memset(expected_value, 0, len);
5352         ink_strlcpy(expected_value, field5Value1, len);
5353         ink_strlcat(expected_value, field5Value1Append, len);
5354         if ((strncmp(fieldValueAppendGet, expected_value, lengthFieldValueAppended) == 0) &&
5355             (lengthFieldValueAppended = strlen(expected_value))) {
5356           SDK_RPRINT(test, "TSMimeHdrFieldValueAppend", "TestCase1", TC_PASS, "ok");
5357           test_passed_Mime_Hdr_Field_Value_Append = true;
5358         } else {
5359           SDK_RPRINT(test, "TSMimeHdrFieldValueAppend", "TestCase1", TC_FAIL, "Values mismatch");
5360         }
5361         TSfree(expected_value);
5362       }
5363 
5364       numberOfValueInField = TSMimeHdrFieldValuesCount(bufp1, mime_loc1, field_loc15);
5365       if (numberOfValueInField == 4) {
5366         SDK_RPRINT(test, "TSMimeHdrFieldValuesCount", "TestCase1", TC_PASS, "ok");
5367         test_passed_Mime_Hdr_Field_Values_Count = true;
5368       } else {
5369         SDK_RPRINT(test, "TSMimeHdrFieldValuesCount", "TestCase1", TC_FAIL, "Values don't match");
5370       }
5371 
5372       if (TSMimeHdrFieldValueDelete(bufp1, mime_loc1, field_loc15, 2) == TS_ERROR) {
5373         SDK_RPRINT(test, "TSMimeHdrFieldValueDelete", "TestCase1", TC_FAIL, "TSMimeHdrFieldValueDelete Returns TS_ERROR");
5374       } else {
5375         fieldValueDeleteGet = TSMimeHdrFieldValueStringGet(bufp1, mime_loc1, field_loc15, 2, &lengthFieldValueDeleteGet);
5376         if ((strncmp(fieldValueDeleteGet, field5Value3, lengthFieldValueDeleteGet) == 0) &&
5377             (lengthFieldValueDeleteGet == static_cast<int>(strlen(field5Value3)))) {
5378           SDK_RPRINT(test, "TSMimeHdrFieldValueDelete", "TestCase1", TC_FAIL,
5379                      "Value not deleted from field or incorrect index deleted from field.");
5380         } else {
5381           SDK_RPRINT(test, "TSMimeHdrFieldValueDelete", "TestCase1", TC_PASS, "ok");
5382           test_passed_Mime_Hdr_Field_Value_Delete = true;
5383         }
5384       }
5385 
5386       if (TSMimeHdrFieldValuesClear(bufp1, mime_loc1, field_loc15) == TS_ERROR) {
5387         SDK_RPRINT(test, "TSMimeHdrFieldValuesClear", "TestCase1", TC_FAIL, "TSMimeHdrFieldValuesClear returns TS_ERROR");
5388       } else {
5389         numberOfValueInField = TSMimeHdrFieldValuesCount(bufp1, mime_loc1, field_loc15);
5390         if (numberOfValueInField == 0) {
5391           SDK_RPRINT(test, "TSMimeHdrFieldValuesClear", "TestCase1", TC_PASS, "ok");
5392           test_passed_Mime_Hdr_Field_Values_Clear = true;
5393         } else {
5394           SDK_RPRINT(test, "TSMimeHdrFieldValuesClear", "TestCase1", TC_FAIL, "Values don't match");
5395         }
5396       }
5397     }
5398 
5399     // TSMimeHdrFieldDestroy
5400     if (TSMimeHdrFieldDestroy(bufp1, mime_loc1, field_loc15) != TS_SUCCESS) {
5401       SDK_RPRINT(test, "TSMimeHdrFieldDestroy", "TestCase1", TC_FAIL, "TSMimeHdrFieldDestroy returns TS_ERROR");
5402     } else {
5403       if ((test_field_loc15 = TSMimeHdrFieldFind(bufp1, mime_loc1, field5Name, -1)) == TS_NULL_MLOC) {
5404         SDK_RPRINT(test, "TSMimeHdrFieldDestroy", "TestCase1", TC_PASS, "ok");
5405         test_passed_Mime_Hdr_Field_Destroy = true;
5406       } else {
5407         SDK_RPRINT(test, "TSMimeHdrFieldDestroy", "TestCase1", TC_FAIL, "Field not destroyed");
5408         if (TSHandleMLocRelease(bufp1, mime_loc1, test_field_loc15) == TS_ERROR) {
5409           SDK_RPRINT(test, "TSMimeHdrFieldDestroy", "TestCase1", TC_FAIL, "Unable to release handle using TSHandleMLocRelease");
5410         }
5411       }
5412       if (TSHandleMLocRelease(bufp1, mime_loc1, field_loc15) == TS_ERROR) {
5413         SDK_RPRINT(test, "TSMimeHdrFieldDestroy", "TestCase2", TC_FAIL, "Unable to release handle using TSHandleMLocRelease");
5414       }
5415     }
5416   } else {
5417     SDK_RPRINT(test, "TSMimeHdrFieldValueAppend", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrFieldCreate has failed");
5418     SDK_RPRINT(test, "TSMimeHdrFieldValueDelete", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrFieldCreate has failed");
5419     SDK_RPRINT(test, "TSMimeHdrFieldValuesCount", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrFieldCreate has failed");
5420     SDK_RPRINT(test, "TSMimeHdrFieldValuesClear", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrFieldCreate has failed");
5421     SDK_RPRINT(test, "TSMimeHdrFieldDestroy", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrFieldCreate has failed");
5422   }
5423 
5424   // Mime Hdr Fields Clear
5425   if (test_passed_Mime_Hdr_Field_Append == true) {
5426     if (TSMimeHdrFieldsClear(bufp1, mime_loc1) != TS_SUCCESS) {
5427       SDK_RPRINT(test, "TSMimeHdrFieldsClear", "TestCase1", TC_FAIL, "TSMimeHdrFieldsClear returns TS_ERROR");
5428     } else {
5429       if ((numberOfFields = TSMimeHdrFieldsCount(bufp1, mime_loc1)) < 0) {
5430         SDK_RPRINT(test, "TSMimeHdrFieldsClear", "TestCase1", TC_FAIL, "TSMimeHdrFieldsCount returns TS_ERROR");
5431       } else {
5432         if (numberOfFields == 0) {
5433           SDK_RPRINT(test, "TSMimeHdrFieldsClear", "TestCase1", TC_PASS, "ok");
5434           test_passed_Mime_Hdr_Fields_Clear = true;
5435         } else {
5436           SDK_RPRINT(test, "TSMimeHdrFieldsClear", "TestCase1", TC_FAIL, "Fields still exist");
5437         }
5438       }
5439       if ((TSHandleMLocRelease(bufp1, mime_loc1, field_loc11) == TS_ERROR) ||
5440           (TSHandleMLocRelease(bufp1, mime_loc1, field_loc12) == TS_ERROR) ||
5441           (TSHandleMLocRelease(bufp1, mime_loc1, field_loc13) == TS_ERROR) ||
5442           (TSHandleMLocRelease(bufp1, mime_loc1, field_loc14) == TS_ERROR)) {
5443         SDK_RPRINT(test, "TSMimeHdrFieldsDestroy", "", TC_FAIL, "Unable to release handle using TSHandleMLocRelease");
5444       }
5445     }
5446   } else {
5447     SDK_RPRINT(test, "TSMimeHdrFieldsClear", "TestCase1", TC_FAIL,
5448                "Cannot run test as Fields have not been inserted in the mime header");
5449   }
5450 
5451   // Mime Hdr Destroy
5452   if (test_passed_Mime_Hdr_Create == true) {
5453     if (TSMimeHdrDestroy(bufp1, mime_loc1) == TS_ERROR) {
5454       SDK_RPRINT(test, "TSMimeHdrDestroy", "TestCase1", TC_FAIL, "TSMimeHdrDestroy return TS_ERROR");
5455       SDK_RPRINT(test, "TSMimeHdrDestroy", "TestCase1", TC_FAIL, "Probably TSMimeHdrCreate failed.");
5456     } else {
5457       SDK_RPRINT(test, "TSMimeHdrDestroy", "TestCase1", TC_PASS, "ok");
5458       test_passed_Mime_Hdr_Destroy = true;
5459     }
5460     /** Commented out as Traffic Server was crashing. Will have to look into it. */
5461     /*
5462        if (TSHandleMLocRelease(bufp1,TS_NULL_MLOC,mime_loc1)==TS_ERROR) {
5463        SDK_RPRINT(test,"TSHandleMLocRelease","TSMimeHdrDestroy",TC_FAIL,"unable to release handle using TSHandleMLocRelease");
5464        }
5465      */
5466   } else {
5467     SDK_RPRINT(test, "TSMimeHdrDestroy", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrCreate failed");
5468   }
5469 
5470   // MBuffer Destroy
5471   if (test_passed_MBuffer_Create == true) {
5472     if (TSMBufferDestroy(bufp1) == TS_ERROR) {
5473       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase1", TC_FAIL, "TSMBufferDestroy return TS_ERROR");
5474       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase1", TC_FAIL, "Probably TSMBufferCreate failed.");
5475     } else {
5476       SDK_RPRINT(test, "TSMBufferDestroy", "TestCase1", TC_PASS, "ok");
5477       test_passed_MBuffer_Destroy = true;
5478     }
5479   } else {
5480     SDK_RPRINT(test, "TSMimeHdrDestroy", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrCreate failed");
5481   }
5482 
5483   if ((test_passed_MBuffer_Create == true) && (test_passed_Mime_Hdr_Create == true) &&
5484       (test_passed_Mime_Hdr_Field_Create == true) && (test_passed_Mime_Hdr_Field_Name == true) &&
5485       (test_passed_Mime_Hdr_Field_Append == true) && (test_passed_Mime_Hdr_Field_Get == true) &&
5486       (test_passed_Mime_Hdr_Field_Next == true) && (test_passed_Mime_Hdr_Fields_Count == true) &&
5487       (test_passed_Mime_Hdr_Field_Value_String_Insert == true) && (test_passed_Mime_Hdr_Field_Value_String_Get == true) &&
5488       (test_passed_Mime_Hdr_Field_Value_String_Set == true) && (test_passed_Mime_Hdr_Field_Value_Date_Insert == true) &&
5489       (test_passed_Mime_Hdr_Field_Value_Date_Get == true) && (test_passed_Mime_Hdr_Field_Value_Date_Set == true) &&
5490       (test_passed_Mime_Hdr_Field_Value_Int_Insert == true) && (test_passed_Mime_Hdr_Field_Value_Int_Get == true) &&
5491       (test_passed_Mime_Hdr_Field_Value_Int_Set == true) && (test_passed_Mime_Hdr_Field_Value_Uint_Insert == true) &&
5492       (test_passed_Mime_Hdr_Field_Value_Uint_Get == true) && (test_passed_Mime_Hdr_Field_Value_Uint_Set == true) &&
5493       (test_passed_Mime_Hdr_Field_Value_Append == true) && (test_passed_Mime_Hdr_Field_Value_Delete == true) &&
5494       (test_passed_Mime_Hdr_Field_Values_Clear == true) && (test_passed_Mime_Hdr_Field_Values_Count == true) &&
5495       (test_passed_Mime_Hdr_Field_Destroy == true) && (test_passed_Mime_Hdr_Fields_Clear == true) &&
5496       (test_passed_Mime_Hdr_Destroy == true) && (test_passed_MBuffer_Destroy == true) &&
5497       (test_passed_Mime_Hdr_Field_Length_Get == true)) {
5498     *pstatus = REGRESSION_TEST_PASSED;
5499   } else {
5500     *pstatus = REGRESSION_TEST_FAILED;
5501   }
5502   return;
5503 }
5504 
5505 //////////////////////////////////////////////
5506 //       SDK_API_TSHttpHdrParse
5507 //
5508 // Unit Test for API: TSHttpParserCreate
5509 //                    TSHttpParserDestroy
5510 //                    TSHttpParserClear
5511 //                    TSHttpHdrParseReq
5512 //                    TSHttpHdrParseResp
5513 //////////////////////////////////////////////
5514 
5515 char *
convert_http_hdr_to_string(TSMBuffer bufp,TSMLoc hdr_loc)5516 convert_http_hdr_to_string(TSMBuffer bufp, TSMLoc hdr_loc)
5517 {
5518   TSIOBuffer output_buffer;
5519   TSIOBufferReader reader;
5520   int64_t total_avail;
5521 
5522   TSIOBufferBlock block;
5523   const char *block_start;
5524   int64_t block_avail;
5525 
5526   char *output_string;
5527   int output_len;
5528 
5529   output_buffer = TSIOBufferCreate();
5530 
5531   if (!output_buffer) {
5532     TSError("[InkAPITest] couldn't allocate IOBuffer");
5533   }
5534 
5535   reader = TSIOBufferReaderAlloc(output_buffer);
5536 
5537   /* This will print  just MIMEFields and not
5538      the http request line */
5539   TSHttpHdrPrint(bufp, hdr_loc, output_buffer);
5540 
5541   /* Find out how the big the complete header is by
5542      seeing the total bytes in the buffer.  We need to
5543      look at the buffer rather than the first block to
5544      see the size of the entire header */
5545   total_avail = TSIOBufferReaderAvail(reader);
5546 
5547   /* Allocate the string with an extra byte for the string
5548      terminator */
5549   output_string = static_cast<char *>(TSmalloc(total_avail + 1));
5550   output_len    = 0;
5551 
5552   /* We need to loop over all the buffer blocks to make
5553      sure we get the complete header since the header can
5554      be in multiple blocks */
5555   block = TSIOBufferReaderStart(reader);
5556   while (block) {
5557     block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
5558 
5559     /* We'll get a block pointer back even if there is no data
5560        left to read so check for this condition and break out of
5561        the loop. A block with no data to read means we've exhausted
5562        buffer of data since if there was more data on a later
5563        block in the chain, this block would have been skipped over */
5564     if (block_avail == 0) {
5565       break;
5566     }
5567 
5568     memcpy(output_string + output_len, block_start, block_avail);
5569     output_len += block_avail;
5570 
5571     /* Consume the data so that we get to the next block */
5572     TSIOBufferReaderConsume(reader, block_avail);
5573 
5574     /* Get the next block now that we've consumed the
5575        data off the last block */
5576     block = TSIOBufferReaderStart(reader);
5577   }
5578 
5579   /* Terminate the string */
5580   output_string[output_len] = '\0';
5581   output_len++;
5582 
5583   /* Free up the TSIOBuffer that we used to print out the header */
5584   TSIOBufferReaderFree(reader);
5585   TSIOBufferDestroy(output_buffer);
5586 
5587   return output_string;
5588 }
5589 
REGRESSION_TEST(SDK_API_TSHttpHdrParse)5590 REGRESSION_TEST(SDK_API_TSHttpHdrParse)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
5591 {
5592   const char *req =
5593     "GET http://www.example.com/ HTTP/1.1\r\nmimefield1:field1value1,field1value2\r\nmimefield2:field2value1,field2value2\r\n\r\n";
5594   const char *resp = "HTTP/1.1 200 OK\r\n1mimefield:1field1value,1field2value\r\n2mimefield:2field1value,2field2value\r\n\r\n";
5595   const char *start;
5596   const char *end;
5597   char *temp;
5598 
5599   int retval;
5600 
5601   TSMBuffer reqbufp;
5602   TSMBuffer respbufp = (TSMBuffer) nullptr;
5603 
5604   TSMLoc req_hdr_loc  = (TSMLoc) nullptr;
5605   TSMLoc resp_hdr_loc = (TSMLoc) nullptr;
5606 
5607   TSHttpParser parser;
5608 
5609   bool test_passed_parse_req      = false;
5610   bool test_passed_parse_resp     = false;
5611   bool test_passed_parser_clear   = false;
5612   bool test_passed_parser_destroy = false;
5613 
5614   // Create Parser
5615   parser = TSHttpParserCreate();
5616   SDK_RPRINT(test, "TSHttpParserCreate", "TestCase1", TC_PASS, "ok");
5617 
5618   // Request
5619   reqbufp     = TSMBufferCreate();
5620   req_hdr_loc = TSHttpHdrCreate(reqbufp);
5621   start       = req;
5622   end         = req + strlen(req) + 1;
5623   if ((retval = TSHttpHdrParseReq(parser, reqbufp, req_hdr_loc, &start, end)) == TS_PARSE_ERROR) {
5624     SDK_RPRINT(test, "TSHttpHdrParseReq", "TestCase1", TC_FAIL, "TSHttpHdrParseReq returns TS_PARSE_ERROR");
5625   } else {
5626     if (retval == TS_PARSE_DONE) {
5627       test_passed_parse_req = true;
5628     } else {
5629       SDK_RPRINT(test, "TSHttpHdrParseReq", "TestCase1", TC_FAIL, "Parsing Error");
5630     }
5631   }
5632 
5633   TSHttpParserClear(parser);
5634   SDK_RPRINT(test, "TSHttpParserClear", "TestCase1", TC_PASS, "ok");
5635   test_passed_parser_clear = true;
5636 
5637   // Response
5638   if (test_passed_parser_clear == true) {
5639     respbufp     = TSMBufferCreate();
5640     resp_hdr_loc = TSHttpHdrCreate(respbufp);
5641     start        = resp;
5642     end          = resp + strlen(resp) + 1;
5643     if ((retval = TSHttpHdrParseResp(parser, respbufp, resp_hdr_loc, &start, end)) == TS_PARSE_ERROR) {
5644       SDK_RPRINT(test, "TSHttpHdrParseResp", "TestCase1", TC_FAIL, "TSHttpHdrParseResp returns TS_PARSE_ERROR.");
5645     } else {
5646       if (retval == TS_PARSE_DONE) {
5647         test_passed_parse_resp = true;
5648       } else {
5649         SDK_RPRINT(test, "TSHttpHdrParseResp", "TestCase1", TC_FAIL, "Parsing Error");
5650       }
5651     }
5652   }
5653 
5654   if (test_passed_parse_req == true) {
5655     temp = convert_http_hdr_to_string(reqbufp, req_hdr_loc);
5656     if (strcmp(req, temp) == 0) {
5657       SDK_RPRINT(test, "TSHttpHdrParseReq", "TestCase1", TC_PASS, "ok");
5658     } else {
5659       SDK_RPRINT(test, "TSHttpHdrParseReq", "TestCase1", TC_FAIL, "Incorrect parsing");
5660       test_passed_parse_req = false;
5661     }
5662     TSfree(temp);
5663   }
5664 
5665   if (test_passed_parse_resp == true) {
5666     temp = convert_http_hdr_to_string(respbufp, resp_hdr_loc);
5667     if (strcmp(resp, temp) == 0) {
5668       SDK_RPRINT(test, "TSHttpHdrParseResp", "TestCase1", TC_PASS, "ok");
5669     } else {
5670       SDK_RPRINT(test, "TSHttpHdrParseResp", "TestCase1", TC_FAIL, "Incorrect parsing");
5671       test_passed_parse_resp = false;
5672     }
5673     TSfree(temp);
5674   }
5675 
5676   TSHttpParserDestroy(parser);
5677   SDK_RPRINT(test, "TSHttpParserDestroy", "TestCase1", TC_PASS, "ok");
5678   test_passed_parser_destroy = true;
5679 
5680   if ((test_passed_parse_req != true) || (test_passed_parse_resp != true) || (test_passed_parser_clear != true) ||
5681       (test_passed_parser_destroy != true)) {
5682     *pstatus = REGRESSION_TEST_FAILED;
5683   } else {
5684     *pstatus = REGRESSION_TEST_PASSED;
5685   }
5686 
5687   TSMimeHdrDestroy(reqbufp, req_hdr_loc);
5688   TSHandleMLocRelease(reqbufp, TS_NULL_MLOC, req_hdr_loc);
5689   TSMBufferDestroy(reqbufp);
5690 
5691   if (resp_hdr_loc) {
5692     TSMimeHdrDestroy(respbufp, resp_hdr_loc);
5693     TSHandleMLocRelease(respbufp, TS_NULL_MLOC, resp_hdr_loc);
5694   }
5695 
5696   if (respbufp) {
5697     TSMBufferDestroy(respbufp);
5698   }
5699 
5700   return;
5701 }
5702 
5703 //////////////////////////////////////////////
5704 //       SDK_API_TSMimeHdrParse
5705 //
5706 // Unit Test for API: TSMimeHdrCopy
5707 //                    TSMimeHdrClone
5708 //                    TSMimeHdrFieldCopy
5709 //                    TSMimeHdrFieldClone
5710 //                    TSMimeHdrFieldCopyValues
5711 //                    TSMimeHdrFieldNextDup
5712 //                    TSMimeHdrFieldRemove
5713 //                    TSMimeHdrLengthGet
5714 //                    TSMimeHdrParse
5715 //                    TSMimeHdrPrint
5716 //                    TSMimeParserClear
5717 //                    TSMimeParserCreate
5718 //                    TSMimeParserDestroy
5719 //                    TSHandleMLocRelease
5720 //////////////////////////////////////////////
5721 
5722 static char *
convert_mime_hdr_to_string(TSMBuffer bufp,TSMLoc hdr_loc)5723 convert_mime_hdr_to_string(TSMBuffer bufp, TSMLoc hdr_loc)
5724 {
5725   TSIOBuffer output_buffer;
5726   TSIOBufferReader reader;
5727   int64_t total_avail;
5728 
5729   TSIOBufferBlock block;
5730   const char *block_start;
5731   int64_t block_avail;
5732 
5733   char *output_string;
5734   int output_len;
5735 
5736   output_buffer = TSIOBufferCreate();
5737 
5738   if (!output_buffer) {
5739     TSError("[InkAPITest] couldn't allocate IOBuffer");
5740   }
5741 
5742   reader = TSIOBufferReaderAlloc(output_buffer);
5743 
5744   /* This will print  just MIMEFields and not
5745      the http request line */
5746   TSMimeHdrPrint(bufp, hdr_loc, output_buffer);
5747 
5748   /* Find out how the big the complete header is by
5749      seeing the total bytes in the buffer.  We need to
5750      look at the buffer rather than the first block to
5751      see the size of the entire header */
5752   total_avail = TSIOBufferReaderAvail(reader);
5753 
5754   /* Allocate the string with an extra byte for the string
5755      terminator */
5756   output_string = static_cast<char *>(TSmalloc(total_avail + 1));
5757   output_len    = 0;
5758 
5759   /* We need to loop over all the buffer blocks to make
5760      sure we get the complete header since the header can
5761      be in multiple blocks */
5762   block = TSIOBufferReaderStart(reader);
5763   while (block) {
5764     block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
5765 
5766     /* We'll get a block pointer back even if there is no data
5767        left to read so check for this condition and break out of
5768        the loop. A block with no data to read means we've exhausted
5769        buffer of data since if there was more data on a later
5770        block in the chain, this block would have been skipped over */
5771     if (block_avail == 0) {
5772       break;
5773     }
5774 
5775     memcpy(output_string + output_len, block_start, block_avail);
5776     output_len += block_avail;
5777 
5778     /* Consume the data so that we get to the next block */
5779     TSIOBufferReaderConsume(reader, block_avail);
5780 
5781     /* Get the next block now that we've consumed the
5782        data off the last block */
5783     block = TSIOBufferReaderStart(reader);
5784   }
5785 
5786   /* Terminate the string */
5787   output_string[output_len] = '\0';
5788   output_len++;
5789 
5790   /* Free up the TSIOBuffer that we used to print out the header */
5791   TSIOBufferReaderFree(reader);
5792   TSIOBufferDestroy(output_buffer);
5793 
5794   return output_string;
5795 }
5796 
5797 TSReturnCode
compare_field_values(RegressionTest * test,TSMBuffer bufp1,TSMLoc hdr_loc1,TSMLoc field_loc1,TSMBuffer bufp2,TSMLoc hdr_loc2,TSMLoc field_loc2)5798 compare_field_values(RegressionTest *test, TSMBuffer bufp1, TSMLoc hdr_loc1, TSMLoc field_loc1, TSMBuffer bufp2, TSMLoc hdr_loc2,
5799                      TSMLoc field_loc2)
5800 {
5801   int no_of_values1;
5802   int no_of_values2;
5803   int i;
5804 
5805   const char *str1 = nullptr;
5806   const char *str2 = nullptr;
5807 
5808   int length1 = 0;
5809   int length2 = 0;
5810 
5811   no_of_values1 = TSMimeHdrFieldValuesCount(bufp1, hdr_loc1, field_loc1);
5812   no_of_values2 = TSMimeHdrFieldValuesCount(bufp2, hdr_loc2, field_loc2);
5813   if (no_of_values1 != no_of_values2) {
5814     SDK_RPRINT(test, "compare_field_values", "TestCase", TC_FAIL, "Field Values not equal");
5815     return TS_ERROR;
5816   }
5817 
5818   for (i = 0; i < no_of_values1; i++) {
5819     str1 = TSMimeHdrFieldValueStringGet(bufp1, hdr_loc1, field_loc1, i, &length1);
5820     str2 = TSMimeHdrFieldValueStringGet(bufp2, hdr_loc2, field_loc2, i, &length2);
5821     if (!((length1 == length2) && (strncmp(str1, str2, length1) == 0))) {
5822       SDK_RPRINT(test, "compare_field_values", "TestCase", TC_FAIL, "Field Value %d differ from each other", i);
5823       return TS_ERROR;
5824     }
5825   }
5826 
5827   return TS_SUCCESS;
5828 }
5829 
REGRESSION_TEST(SDK_API_TSMimeHdrParse)5830 REGRESSION_TEST(SDK_API_TSMimeHdrParse)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
5831 {
5832   const char *parse_string =
5833     "field1:field1Value1,field1Value2\r\nfield2:10,-34,45\r\nfield3:field3Value1,23\r\nfield2: 2345, field2Value2\r\n\r\n";
5834   const char *DUPLICATE_FIELD_NAME = "field2";
5835   const char *REMOVE_FIELD_NAME    = "field3";
5836 
5837   TSMimeParser parser;
5838 
5839   TSMBuffer bufp1 = (TSMBuffer) nullptr;
5840   TSMBuffer bufp2 = (TSMBuffer) nullptr;
5841   TSMBuffer bufp3 = (TSMBuffer) nullptr;
5842 
5843   TSMLoc mime_hdr_loc1 = (TSMLoc) nullptr;
5844   TSMLoc mime_hdr_loc2 = (TSMLoc) nullptr;
5845   TSMLoc mime_hdr_loc3 = (TSMLoc) nullptr;
5846 
5847   TSMLoc field_loc1 = (TSMLoc) nullptr;
5848   TSMLoc field_loc2 = (TSMLoc) nullptr;
5849 
5850   const char *start;
5851   const char *end;
5852   char *temp;
5853 
5854   TSParseResult retval;
5855   int hdrLength;
5856 
5857   bool test_passed_parse                      = false;
5858   bool test_passed_parser_clear               = false;
5859   bool test_passed_parser_destroy             = false;
5860   bool test_passed_mime_hdr_print             = false;
5861   bool test_passed_mime_hdr_length_get        = false;
5862   bool test_passed_mime_hdr_field_next_dup    = false;
5863   bool test_passed_mime_hdr_copy              = false;
5864   bool test_passed_mime_hdr_field_remove      = false;
5865   bool test_passed_mime_hdr_field_copy        = false;
5866   bool test_passed_mime_hdr_field_copy_values = false;
5867   bool test_passed_handle_mloc_release        = false;
5868   bool test_passed_mime_hdr_field_find        = false;
5869 
5870   // Create Parser
5871   parser = TSMimeParserCreate();
5872   SDK_RPRINT(test, "TSMimeParserCreate", "TestCase1", TC_PASS, "ok");
5873 
5874   // Parsing
5875   bufp1 = TSMBufferCreate();
5876   if (TSMimeHdrCreate(bufp1, &mime_hdr_loc1) != TS_SUCCESS) {
5877     SDK_RPRINT(test, "TSMimeHdrParse", "TestCase1", TC_FAIL, "Cannot create Mime hdr for parsing");
5878     SDK_RPRINT(test, "TSMimeHdrPrint", "TestCase1", TC_FAIL, "Cannot run test as unable to create Mime Header for parsing");
5879     SDK_RPRINT(test, "TSMimeHdrLengthGet", "TestCase1", TC_FAIL, "Cannot run test as unable to create Mime Header for parsing");
5880 
5881     if (TSMBufferDestroy(bufp1) == TS_ERROR) {
5882       SDK_RPRINT(test, "TSMimeHdrParse", "TestCase1", TC_FAIL, "Error in Destroying MBuffer");
5883     }
5884   } else {
5885     start = parse_string;
5886     end   = parse_string + strlen(parse_string) + 1;
5887     if ((retval = TSMimeHdrParse(parser, bufp1, mime_hdr_loc1, &start, end)) == TS_PARSE_ERROR) {
5888       SDK_RPRINT(test, "TSMimeHdrParse", "TestCase1", TC_FAIL, "TSMimeHdrParse returns TS_PARSE_ERROR");
5889       SDK_RPRINT(test, "TSMimeHdrPrint", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrParse returned Error.");
5890       SDK_RPRINT(test, "TSMimeHdrLengthGet", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrParse returned Error.");
5891     } else {
5892       if (retval == TS_PARSE_DONE) {
5893         temp = convert_mime_hdr_to_string(bufp1, mime_hdr_loc1); // Implements TSMimeHdrPrint.
5894         if (strcmp(parse_string, temp) == 0) {
5895           SDK_RPRINT(test, "TSMimeHdrParse", "TestCase1", TC_PASS, "ok");
5896           SDK_RPRINT(test, "TSMimeHdrPrint", "TestCase1", TC_PASS, "ok");
5897 
5898           // TSMimeHdrLengthGet
5899           hdrLength = TSMimeHdrLengthGet(bufp1, mime_hdr_loc1);
5900           if (hdrLength == static_cast<int>(strlen(temp))) {
5901             SDK_RPRINT(test, "TSMimeHdrLengthGet", "TestCase1", TC_PASS, "ok");
5902             test_passed_mime_hdr_length_get = true;
5903           } else {
5904             SDK_RPRINT(test, "TSMimeHdrLengthGet", "TestCase1", TC_FAIL, "Value's Mismatch");
5905           }
5906 
5907           test_passed_parse          = true;
5908           test_passed_mime_hdr_print = true;
5909         } else {
5910           SDK_RPRINT(test, "TSMimeHdrParse|TSMimeHdrPrint", "TestCase1", TC_FAIL, "Incorrect parsing or incorrect Printing");
5911           SDK_RPRINT(test, "TSMimeHdrLengthGet", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrParse|TSMimeHdrPrint failed.");
5912         }
5913 
5914         TSfree(temp);
5915       } else {
5916         SDK_RPRINT(test, "TSMimeHdrParse", "TestCase1", TC_FAIL, "Parsing Error");
5917         SDK_RPRINT(test, "TSMimeHdrPrint", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrParse returned error.");
5918         SDK_RPRINT(test, "TSMimeHdrLengthGet", "TestCase1", TC_FAIL, "Cannot run test as TSMimeHdrParse returned error.");
5919       }
5920     }
5921   }
5922 
5923   TSMimeParserClear(parser);
5924   SDK_RPRINT(test, "TSMimeParserClear", "TestCase1", TC_PASS, "ok");
5925   test_passed_parser_clear = true;
5926 
5927   TSMimeParserDestroy(parser);
5928   SDK_RPRINT(test, "TSMimeParserDestroy", "TestCase1", TC_PASS, "ok");
5929   test_passed_parser_destroy = true;
5930 
5931   // TSMimeHdrFieldNextDup
5932   if (test_passed_parse == true) {
5933     if ((field_loc1 = TSMimeHdrFieldFind(bufp1, mime_hdr_loc1, DUPLICATE_FIELD_NAME, -1)) == TS_NULL_MLOC) {
5934       SDK_RPRINT(test, "TSMimeHdrFieldNextDup", "TestCase1", TC_FAIL, "TSMimeHdrFieldFind returns TS_NULL_MLOC");
5935       SDK_RPRINT(test, "TSMimeHdrFieldFind", "TestCase1", TC_PASS, "TSMimeHdrFieldFind returns TS_NULL_MLOC");
5936     } else {
5937       const char *fieldName;
5938       int length;
5939 
5940       fieldName = TSMimeHdrFieldNameGet(bufp1, mime_hdr_loc1, field_loc1, &length);
5941       if (strncmp(fieldName, DUPLICATE_FIELD_NAME, length) == 0) {
5942         SDK_RPRINT(test, "TSMimeHdrFieldFind", "TestCase1", TC_PASS, "ok");
5943         test_passed_mime_hdr_field_find = true;
5944       } else {
5945         SDK_RPRINT(test, "TSMimeHdrFieldFind", "TestCase1", TC_PASS, "TSMimeHdrFieldFind returns incorrect field pointer");
5946       }
5947 
5948       field_loc2 = TSMimeHdrFieldNextDup(bufp1, mime_hdr_loc1, field_loc1);
5949       if (compare_field_names(test, bufp1, mime_hdr_loc1, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
5950         SDK_RPRINT(test, "TSMimeHdrFieldNextDup", "TestCase1", TC_FAIL, "Incorrect Pointer");
5951       } else {
5952         SDK_RPRINT(test, "TSMimeHdrFieldNextDup", "TestCase1", TC_PASS, "ok");
5953         test_passed_mime_hdr_field_next_dup = true;
5954       }
5955 
5956       // TSHandleMLocRelease
5957       if (TSHandleMLocRelease(bufp1, mime_hdr_loc1, field_loc1) == TS_ERROR) {
5958         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase1", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
5959       } else {
5960         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase1", TC_PASS, "ok");
5961         test_passed_handle_mloc_release = true;
5962       }
5963 
5964       if (field_loc2 != nullptr) {
5965         if (TSHandleMLocRelease(bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
5966           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase2", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
5967           test_passed_handle_mloc_release = false;
5968         } else {
5969           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase2", TC_PASS, "ok");
5970         }
5971       }
5972     }
5973   } else {
5974     SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase1", TC_FAIL, "Unable to run test as parsing failed.");
5975   }
5976 
5977   // TSMimeHdrCopy
5978   if (test_passed_parse == true) {
5979     // Parsing
5980     bufp2 = TSMBufferCreate();
5981     if (TSMimeHdrCreate(bufp2, &mime_hdr_loc2) != TS_SUCCESS) {
5982       SDK_RPRINT(test, "TSMimeHdrCopy", "TestCase1", TC_FAIL, "Cannot create Mime hdr for copying");
5983       if (TSMBufferDestroy(bufp2) == TS_ERROR) {
5984         SDK_RPRINT(test, "TSMimeHdrCopy", "TestCase1", TC_FAIL, "Error in Destroying MBuffer");
5985       }
5986     } else {
5987       if (TSMimeHdrCopy(bufp2, mime_hdr_loc2, bufp1, mime_hdr_loc1) == TS_ERROR) {
5988         SDK_RPRINT(test, "TSMimeHdrCopy", "TestCase1", TC_FAIL, "TSMimeHdrCopy returns TS_ERROR");
5989       } else {
5990         temp = convert_mime_hdr_to_string(bufp2, mime_hdr_loc2); // Implements TSMimeHdrPrint.
5991         if (strcmp(parse_string, temp) == 0) {
5992           SDK_RPRINT(test, "TSMimeHdrCopy", "TestCase1", TC_PASS, "ok");
5993           test_passed_mime_hdr_copy = true;
5994         } else {
5995           SDK_RPRINT(test, "TSMimeHdrCopy", "TestCase1", TC_FAIL, "Value's Mismatch");
5996         }
5997         TSfree(temp);
5998       }
5999     }
6000   } else {
6001     SDK_RPRINT(test, "TSMimeHdrCopy", "TestCase1", TC_FAIL, "Unable to run test as parsing failed.");
6002   }
6003 
6004   bufp3 = TSMBufferCreate();
6005   TSMimeHdrCreate(bufp3, &mime_hdr_loc3);
6006 
6007   // TSMimeHdrFieldRemove
6008   if (test_passed_mime_hdr_copy == true) {
6009     if ((field_loc1 = TSMimeHdrFieldFind(bufp2, mime_hdr_loc2, REMOVE_FIELD_NAME, -1)) == TS_NULL_MLOC) {
6010       SDK_RPRINT(test, "TSMimeHdrFieldRemove", "TestCase1", TC_FAIL, "TSMimeHdrFieldFind returns TS_NULL_MLOC");
6011     } else {
6012       if (TSMimeHdrFieldRemove(bufp2, mime_hdr_loc2, field_loc1) != TS_SUCCESS) {
6013         SDK_RPRINT(test, "TSMimeHdrFieldRemove", "TestCase1", TC_FAIL, "TSMimeHdrFieldRemove returns TS_ERROR");
6014       } else {
6015         // Make sure the remove actually took effect
6016         field_loc2 = TSMimeHdrFieldFind(bufp2, mime_hdr_loc2, REMOVE_FIELD_NAME, -1);
6017         if ((field_loc2 == TS_NULL_MLOC) || (field_loc1 != field_loc2)) {
6018           test_passed_mime_hdr_field_remove = true;
6019         } else {
6020           SDK_RPRINT(test, "TSMimeHdrFieldRemove", "TestCase1", TC_FAIL, "Field Not Removed");
6021         }
6022 
6023         if (test_passed_mime_hdr_field_remove == true) {
6024           if (TSMimeHdrFieldAppend(bufp2, mime_hdr_loc2, field_loc1) != TS_SUCCESS) {
6025             SDK_RPRINT(test, "TSMimeHdrFieldRemove", "TestCase1", TC_FAIL,
6026                        "Unable to readd the field to mime header. Probably destroyed");
6027             test_passed_mime_hdr_field_remove = false;
6028           } else {
6029             SDK_RPRINT(test, "TSMimeHdrFieldRemove", "TestCase1", TC_PASS, "ok");
6030           }
6031         }
6032       }
6033 
6034       // TSHandleMLocRelease
6035       if (TSHandleMLocRelease(bufp2, mime_hdr_loc2, field_loc1) == TS_ERROR) {
6036         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase3", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6037         test_passed_handle_mloc_release = false;
6038       } else {
6039         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase3", TC_PASS, "ok");
6040       }
6041 
6042       if (field_loc2 != nullptr) {
6043         if (TSHandleMLocRelease(bufp2, mime_hdr_loc2, field_loc2) == TS_ERROR) {
6044           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase4", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6045           test_passed_handle_mloc_release = false;
6046         } else {
6047           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase4", TC_PASS, "ok");
6048         }
6049       }
6050     }
6051   } else {
6052     SDK_RPRINT(test, "TSMimeHdrFieldNext", "TestCase1", TC_FAIL, "Unable to run test as parsing failed.");
6053   }
6054 
6055   // TSMimeHdrFieldCopy
6056   if (test_passed_mime_hdr_copy == true) {
6057     if (TSMimeHdrFieldCreate(bufp2, mime_hdr_loc2, &field_loc1) != TS_SUCCESS) {
6058       SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_FAIL, "Unable to create field for Copying");
6059     } else {
6060       if ((field_loc2 = TSMimeHdrFieldGet(bufp1, mime_hdr_loc1, 0)) == TS_NULL_MLOC) {
6061         SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_FAIL, "Unable to get source field for copying");
6062       } else {
6063         if (TSMimeHdrFieldCopy(bufp2, mime_hdr_loc2, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
6064           SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_FAIL, "TSMimeHdrFieldCopy returns TS_ERROR");
6065         } else {
6066           if ((compare_field_names(test, bufp2, mime_hdr_loc2, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) ||
6067               (compare_field_values(test, bufp2, mime_hdr_loc2, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR)) {
6068             SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_FAIL, "Value's Mismatch");
6069           } else {
6070             SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_PASS, "ok");
6071             test_passed_mime_hdr_field_copy = true;
6072           }
6073         }
6074       }
6075       if (TSHandleMLocRelease(bufp2, mime_hdr_loc2, field_loc1) == TS_ERROR) {
6076         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase5", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6077         test_passed_handle_mloc_release = false;
6078       } else {
6079         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase5", TC_PASS, "ok");
6080       }
6081 
6082       if (field_loc2 != nullptr) {
6083         if (TSHandleMLocRelease(bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
6084           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase6", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6085           test_passed_handle_mloc_release = false;
6086         } else {
6087           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase6", TC_PASS, "ok");
6088         }
6089       }
6090     }
6091   } else {
6092     SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_FAIL, "Unable to run test as bufp2 might not have been created");
6093   }
6094 
6095   // TSMimeHdrFieldClone
6096   field_loc1 = nullptr;
6097   field_loc2 = nullptr;
6098   if ((field_loc2 = TSMimeHdrFieldGet(bufp1, mime_hdr_loc1, 0)) == TS_NULL_MLOC) {
6099     SDK_RPRINT(test, "TSMimeHdrFieldClone", "TestCase1", TC_FAIL, "Unable to get source field for copying");
6100   } else {
6101     if (TSMimeHdrFieldClone(bufp3, mime_hdr_loc3, bufp1, mime_hdr_loc1, field_loc2, &field_loc1) != TS_SUCCESS) {
6102       SDK_RPRINT(test, "TSMimeHdrFieldClone", "TestCase1", TC_FAIL, "TSMimeHdrFieldClone returns TS_ERROR");
6103     } else {
6104       if ((compare_field_names(test, bufp3, mime_hdr_loc3, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) ||
6105           (compare_field_values(test, bufp3, mime_hdr_loc3, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR)) {
6106         SDK_RPRINT(test, "TSMimeHdrFieldClone", "TestCase1", TC_FAIL, "Value's Mismatch");
6107       } else {
6108         SDK_RPRINT(test, "TSMimeHdrFieldClone", "TestCase1", TC_PASS, "ok");
6109       }
6110     }
6111   }
6112   if (field_loc1 != nullptr) {
6113     if (TSHandleMLocRelease(bufp3, mime_hdr_loc3, field_loc1) == TS_ERROR) {
6114       SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase7", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6115       test_passed_handle_mloc_release = false;
6116     } else {
6117       SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase7", TC_PASS, "ok");
6118     }
6119   }
6120 
6121   if (field_loc2 != nullptr) {
6122     if (TSHandleMLocRelease(bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
6123       SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase8", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6124       test_passed_handle_mloc_release = false;
6125     } else {
6126       SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase8", TC_PASS, "ok");
6127     }
6128   }
6129 
6130   // TSMimeHdrFieldCopyValues
6131   if (test_passed_mime_hdr_copy == true) {
6132     if (TSMimeHdrFieldCreate(bufp2, mime_hdr_loc2, &field_loc1) != TS_SUCCESS) {
6133       SDK_RPRINT(test, "TSMimeHdrFieldCopyValues", "TestCase1", TC_FAIL, "Unable to create field for Copying");
6134     } else {
6135       if ((field_loc2 = TSMimeHdrFieldGet(bufp1, mime_hdr_loc1, 0)) == TS_NULL_MLOC) {
6136         SDK_RPRINT(test, "TSMimeHdrFieldCopyValues", "TestCase1", TC_FAIL, "Unable to get source field for copying");
6137       } else {
6138         if (TSMimeHdrFieldCopyValues(bufp2, mime_hdr_loc2, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
6139           SDK_RPRINT(test, "TSMimeHdrFieldCopyValues", "TestCase1", TC_FAIL, "TSMimeHdrFieldCopy returns TS_ERROR");
6140         } else {
6141           if (compare_field_values(test, bufp2, mime_hdr_loc2, field_loc1, bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
6142             SDK_RPRINT(test, "TSMimeHdrFieldCopyValues", "TestCase1", TC_FAIL, "Value's Mismatch");
6143           } else {
6144             SDK_RPRINT(test, "TSMimeHdrFieldCopyValues", "TestCase1", TC_PASS, "ok");
6145             test_passed_mime_hdr_field_copy_values = true;
6146           }
6147         }
6148       }
6149       if (TSHandleMLocRelease(bufp2, mime_hdr_loc2, field_loc1) == TS_ERROR) {
6150         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase9", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6151         test_passed_handle_mloc_release = false;
6152       } else {
6153         SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase9", TC_PASS, "ok");
6154       }
6155 
6156       if (field_loc2 != nullptr) {
6157         if (TSHandleMLocRelease(bufp1, mime_hdr_loc1, field_loc2) == TS_ERROR) {
6158           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase10", TC_FAIL, "TSHandleMLocRelease returns TS_ERROR");
6159           test_passed_handle_mloc_release = false;
6160         } else {
6161           SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase10", TC_PASS, "ok");
6162         }
6163       }
6164     }
6165   } else {
6166     SDK_RPRINT(test, "TSMimeHdrFieldCopy", "TestCase1", TC_FAIL, "Unable to run test as bufp2 might not have been created");
6167   }
6168 
6169   if ((TSMimeHdrDestroy(bufp1, mime_hdr_loc1) == TS_ERROR) || (TSMimeHdrDestroy(bufp2, mime_hdr_loc2) == TS_ERROR) ||
6170       (TSMimeHdrDestroy(bufp3, mime_hdr_loc3) == TS_ERROR)) {
6171     SDK_RPRINT(test, "", "TestCase", TC_FAIL, "TSMimeHdrDestroy returns TS_ERROR");
6172   }
6173 
6174   if (TSHandleMLocRelease(bufp1, TS_NULL_MLOC, mime_hdr_loc1) == TS_ERROR) {
6175     SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase11|12|13", TC_FAIL, "Unable to release mime_hdr_loc1 to Mime Hdrs");
6176     test_passed_handle_mloc_release = false;
6177   }
6178 
6179   if (TSHandleMLocRelease(bufp2, TS_NULL_MLOC, mime_hdr_loc2) == TS_ERROR) {
6180     SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase11|12|13", TC_FAIL, "Unable to release mime_hdr_loc2 to Mime Hdrs");
6181     test_passed_handle_mloc_release = false;
6182   }
6183 
6184   if (TSHandleMLocRelease(bufp3, TS_NULL_MLOC, mime_hdr_loc3) == TS_ERROR) {
6185     SDK_RPRINT(test, "TSHandleMLocRelease", "TestCase11|12|13", TC_FAIL, "Unable to release mime_hdr_loc3 to Mime Hdrs");
6186     test_passed_handle_mloc_release = false;
6187   }
6188 
6189   if (TSMBufferDestroy(bufp1) == TS_ERROR) {
6190     SDK_RPRINT(test, "", "TestCase", TC_FAIL, "TSMBufferDestroy(bufp1) returns TS_ERROR");
6191   }
6192 
6193   if (TSMBufferDestroy(bufp2) == TS_ERROR) {
6194     SDK_RPRINT(test, "", "TestCase", TC_FAIL, "TSMBufferDestroy(bufp2) returns TS_ERROR");
6195   }
6196 
6197   if (TSMBufferDestroy(bufp3) == TS_ERROR) {
6198     SDK_RPRINT(test, "", "TestCase", TC_FAIL, "TSMBufferDestroy(bufp3) returns TS_ERROR");
6199   }
6200 
6201   if ((test_passed_parse != true) || (test_passed_parser_clear != true) || (test_passed_parser_destroy != true) ||
6202       (test_passed_mime_hdr_print != true) || (test_passed_mime_hdr_length_get != true) ||
6203       (test_passed_mime_hdr_field_next_dup != true) || (test_passed_mime_hdr_copy != true) ||
6204       (test_passed_mime_hdr_field_remove != true) || (test_passed_mime_hdr_field_copy != true) ||
6205       (test_passed_mime_hdr_field_copy_values != true) || (test_passed_handle_mloc_release != true) ||
6206       (test_passed_mime_hdr_field_find != true)) {
6207     *pstatus = REGRESSION_TEST_FAILED;
6208   } else {
6209     *pstatus = REGRESSION_TEST_PASSED;
6210   }
6211 }
6212 
6213 //////////////////////////////////////////////
6214 //       SDK_API_TSUrlParse
6215 //
6216 // Unit Test for API: TSUrlParse
6217 //////////////////////////////////////////////
6218 
REGRESSION_TEST(SDK_API_TSUrlParse)6219 REGRESSION_TEST(SDK_API_TSUrlParse)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
6220 {
6221   static const char *const urls[] = {
6222     "file:///test.dat;ab?abc=def#abc",
6223     "http://www.example.com/",
6224     "http://abc:def@www.example.com/",
6225     "http://www.example.com:3426/",
6226     "http://abc:def@www.example.com:3426/",
6227     "http://www.example.com/homepage.cgi",
6228     "http://www.example.com/homepage.cgi;ab?abc=def#abc",
6229     "http://abc:def@www.example.com:3426/homepage.cgi;ab?abc=def#abc",
6230     "https://abc:def@www.example.com:3426/homepage.cgi;ab?abc=def#abc",
6231     "ftp://abc:def@www.example.com:3426/homepage.cgi;ab?abc=def#abc",
6232     "file:///c:/test.dat;ab?abc=def#abc", // Note: file://c: is malformed URL because no host is present.
6233     "file:///test.dat;ab?abc=def#abc",
6234     "foo://bar.com/baz/",
6235     "http://a.b.com/xx.jpg?newpath=http://b.c.com" // https://issues.apache.org/jira/browse/TS-1635
6236   };
6237 
6238   static int const num_urls  = sizeof(urls) / sizeof(urls[0]);
6239   bool test_passed[num_urls] = {false};
6240 
6241   const char *start;
6242   const char *end;
6243   char *temp;
6244 
6245   int retval;
6246 
6247   TSMBuffer bufp;
6248   TSMLoc url_loc = (TSMLoc) nullptr;
6249   int length;
6250 
6251   *pstatus = REGRESSION_TEST_INPROGRESS;
6252 
6253   int idx;
6254   for (idx = 0; idx < num_urls; idx++) {
6255     const char *url = urls[idx];
6256 
6257     bufp = TSMBufferCreate();
6258     if (TSUrlCreate(bufp, &url_loc) != TS_SUCCESS) {
6259       SDK_RPRINT(test, "TSUrlParse", url, TC_FAIL, "Cannot create Url for parsing the url");
6260       if (TSMBufferDestroy(bufp) == TS_ERROR) {
6261         SDK_RPRINT(test, "TSUrlParse", url, TC_FAIL, "Error in Destroying MBuffer");
6262       }
6263     } else {
6264       start = url;
6265       end   = url + strlen(url);
6266       if ((retval = TSUrlParse(bufp, url_loc, &start, end)) == TS_PARSE_ERROR) {
6267         SDK_RPRINT(test, "TSUrlParse", url, TC_FAIL, "TSUrlParse returns TS_PARSE_ERROR");
6268       } else {
6269         if (retval == TS_PARSE_DONE) {
6270           temp = TSUrlStringGet(bufp, url_loc, &length);
6271           if (strncmp(url, temp, length) == 0) {
6272             SDK_RPRINT(test, "TSUrlParse", url, TC_PASS, "ok");
6273             test_passed[idx] = true;
6274           } else {
6275             SDK_RPRINT(test, "TSUrlParse", url, TC_FAIL, "Value's Mismatch");
6276           }
6277           TSfree(temp);
6278         } else {
6279           SDK_RPRINT(test, "TSUrlParse", url, TC_FAIL, "Parsing Error");
6280         }
6281       }
6282     }
6283 
6284     TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
6285     TSMBufferDestroy(bufp);
6286   }
6287 
6288   for (idx = 0; idx < num_urls; idx++) {
6289     if (test_passed[idx] != true) {
6290       *pstatus = REGRESSION_TEST_FAILED;
6291       break;
6292     }
6293   }
6294 
6295   if (idx >= num_urls) {
6296     *pstatus = REGRESSION_TEST_PASSED;
6297   }
6298 
6299   return;
6300 }
6301 
6302 //////////////////////////////////////////////
6303 //       SDK_API_TSTextLog
6304 //
6305 // Unit Test for APIs: TSTextLogObjectCreate
6306 //                     TSTextLogObjectWrite
6307 //                     TSTextLogObjectDestroy
6308 //                     TSTextLogObjectFlush
6309 //////////////////////////////////////////////
6310 #define LOG_TEST_PATTERN "SDK team rocks"
6311 
6312 struct LogTestData {
6313   RegressionTest *test;
6314   int *pstatus;
6315   char *fullpath_logname;
6316   unsigned long magic;
6317   TSTextLogObject log;
6318 };
6319 
6320 static int
log_test_handler(TSCont contp,TSEvent event,void *)6321 log_test_handler(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
6322 {
6323   TSFile filep;
6324   char buf[1024];
6325   bool str_found;
6326   int retVal = 0;
6327 
6328   TSAssert(event == TS_EVENT_TIMEOUT);
6329 
6330   LogTestData *data = static_cast<LogTestData *>(TSContDataGet(contp));
6331   TSAssert(data->magic == MAGIC_ALIVE);
6332 
6333   // Verify content was correctly written into log file
6334 
6335   if ((filep = TSfopen(data->fullpath_logname, "r")) == nullptr) {
6336     SDK_RPRINT(data->test, "TSTextLogObject", "TestCase1", TC_FAIL, "can not open log file %s", data->fullpath_logname);
6337     *(data->pstatus) = REGRESSION_TEST_FAILED;
6338     return -1;
6339   } else {
6340     // The logfile is created
6341     str_found = false;
6342     while (TSfgets(filep, buf, 1024) != nullptr) {
6343       if (strstr(buf, LOG_TEST_PATTERN) != nullptr) {
6344         str_found = true;
6345         break;
6346       }
6347     }
6348     TSfclose(filep);
6349     if (str_found == false) {
6350       SDK_RPRINT(data->test, "TSTextLogObject", "TestCase1", TC_FAIL, "can not find pattern %s in log file", LOG_TEST_PATTERN);
6351       *(data->pstatus) = REGRESSION_TEST_FAILED;
6352       return -1;
6353     }
6354   }
6355 
6356   retVal = TSTextLogObjectDestroy(data->log);
6357   if (retVal != TS_SUCCESS) {
6358     SDK_RPRINT(data->test, "TSTextLogObjectDestroy", "TestCase1", TC_FAIL, "can not destroy log object");
6359     *(data->pstatus) = REGRESSION_TEST_FAILED;
6360     return -1;
6361   } else {
6362     SDK_RPRINT(data->test, "TSTextLogObjectDestroy", "TestCase1", TC_PASS, "ok");
6363   }
6364 
6365   *(data->pstatus) = REGRESSION_TEST_PASSED;
6366   SDK_RPRINT(data->test, "TSTextLogObject", "TestCase1", TC_PASS, "ok");
6367 
6368   // figure out the metainfo file for cleanup.
6369   // code from MetaInfo::_build_name(const char *filename)
6370   int i = -1, l = 0;
6371   char c;
6372   while (c = data->fullpath_logname[l], c != 0) {
6373     if (c == '/') {
6374       i = l;
6375     }
6376     ++l;
6377   }
6378 
6379   // 7 = 1 (dot at beginning) + 5 (".meta") + 1 (null terminating)
6380   //
6381   char *meta_filename = static_cast<char *>(ats_malloc(l + 7));
6382 
6383   if (i < 0) {
6384     ink_string_concatenate_strings(meta_filename, ".", data->fullpath_logname, ".meta", NULL);
6385   } else {
6386     memcpy(meta_filename, data->fullpath_logname, i + 1);
6387     ink_string_concatenate_strings(&meta_filename[i + 1], ".", &data->fullpath_logname[i + 1], ".meta", NULL);
6388   }
6389 
6390   unlink(data->fullpath_logname);
6391   unlink(meta_filename);
6392   TSfree(data->fullpath_logname);
6393   TSfree(meta_filename);
6394   meta_filename = nullptr;
6395 
6396   data->magic = MAGIC_DEAD;
6397   TSfree(data);
6398   data = nullptr;
6399 
6400   return -1;
6401 }
6402 
REGRESSION_TEST(SDK_API_TSTextLog)6403 REGRESSION_TEST(SDK_API_TSTextLog)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
6404 {
6405   *pstatus = REGRESSION_TEST_INPROGRESS;
6406 
6407   TSTextLogObject log;
6408   TSReturnCode retVal;
6409 
6410   char logname[PATH_NAME_MAX];
6411   char fullpath_logname[PATH_NAME_MAX];
6412 
6413   /* Generate a random log file name, so if we run the test several times, we won't use the
6414      same log file name. */
6415   ats_scoped_str tmp(RecConfigReadLogDir());
6416   snprintf(logname, sizeof(logname), "RegressionTestLog%d.log", static_cast<int>(getpid()));
6417   snprintf(fullpath_logname, sizeof(fullpath_logname), "%s/%s", (const char *)tmp, logname);
6418 
6419   unlink(fullpath_logname);
6420   retVal = TSTextLogObjectCreate(logname, TS_LOG_MODE_ADD_TIMESTAMP, &log);
6421   if (retVal != TS_SUCCESS) {
6422     SDK_RPRINT(test, "TSTextLogObjectCreate", "TestCase1", TC_FAIL, "can not create log object");
6423     *pstatus = REGRESSION_TEST_FAILED;
6424     return;
6425   } else {
6426     SDK_RPRINT(test, "TSTextLogObjectCreate", "TestCase1", TC_PASS, "ok");
6427   }
6428 
6429   retVal = TSTextLogObjectWrite(log, (char *)LOG_TEST_PATTERN);
6430   if (retVal != TS_SUCCESS) {
6431     SDK_RPRINT(test, "TSTextLogObjectWrite", "TestCase1", TC_FAIL, "can not write to log object");
6432     *pstatus = REGRESSION_TEST_FAILED;
6433     return;
6434   } else {
6435     SDK_RPRINT(test, "TSTextLogObjectWrite", "TestCase1", TC_PASS, "ok");
6436   }
6437 
6438   TSTextLogObjectFlush(log);
6439   SDK_RPRINT(test, "TSTextLogObjectFlush", "TestCase1", TC_PASS, "ok");
6440 
6441   TSCont log_test_cont   = TSContCreate(log_test_handler, TSMutexCreate());
6442   LogTestData *data      = static_cast<LogTestData *>(TSmalloc(sizeof(LogTestData)));
6443   data->test             = test;
6444   data->pstatus          = pstatus;
6445   data->fullpath_logname = TSstrdup(fullpath_logname);
6446   data->magic            = MAGIC_ALIVE;
6447   data->log              = log;
6448   TSContDataSet(log_test_cont, data);
6449 
6450   TSContScheduleOnPool(log_test_cont, 6000, TS_THREAD_POOL_NET);
6451   return;
6452 }
6453 
6454 //////////////////////////////////////////////
6455 //       SDK_API_TSMgmtGet
6456 //
6457 // Unit Test for APIs: TSMgmtCounterGet
6458 //                     TSMgmtFloatGet
6459 //                     TSMgmtIntGet
6460 //                     TSMgmtStringGet
6461 //                     TSMgmtDataTypeGet
6462 //////////////////////////////////////////////
6463 
REGRESSION_TEST(SDK_API_TSMgmtGet)6464 REGRESSION_TEST(SDK_API_TSMgmtGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
6465 {
6466   const char *CONFIG_PARAM_COUNTER_NAME = "proxy.process.ssl.total_tickets_renewed";
6467   int CONFIG_PARAM_COUNTER_VALUE        = 0;
6468 
6469   const char *CONFIG_PARAM_FLOAT_NAME = "proxy.config.http.background_fill_completed_threshold";
6470   float CONFIG_PARAM_FLOAT_VALUE      = 0.0;
6471 
6472   const char *CONFIG_PARAM_INT_NAME = "proxy.config.http.cache.http";
6473   int CONFIG_PARAM_INT_VALUE        = 1;
6474 
6475   const char *CONFIG_PARAM_STRING_NAME  = "proxy.config.product_name";
6476   const char *CONFIG_PARAM_STRING_VALUE = "Traffic Server";
6477 
6478   *pstatus = REGRESSION_TEST_INPROGRESS;
6479 
6480   int err              = 0;
6481   TSMgmtCounter cvalue = 0;
6482   TSMgmtFloat fvalue   = 0.0;
6483   TSMgmtInt ivalue     = -1;
6484   TSMgmtString svalue  = nullptr;
6485 
6486   if (TS_SUCCESS != TSMgmtCounterGet(CONFIG_PARAM_COUNTER_NAME, &cvalue)) {
6487     SDK_RPRINT(test, "TSMgmtCounterGet", "TestCase1.1", TC_FAIL, "can not get value of param %s", CONFIG_PARAM_COUNTER_NAME);
6488     err = 1;
6489   } else if (cvalue != CONFIG_PARAM_COUNTER_VALUE) {
6490     SDK_RPRINT(test, "TSMgmtCounterGet", "TestCase1.1", TC_FAIL, "got incorrect value of param %s, should have been %d, found %d",
6491                CONFIG_PARAM_COUNTER_NAME, CONFIG_PARAM_COUNTER_VALUE, cvalue);
6492     err = 1;
6493   } else {
6494     SDK_RPRINT(test, "TSMgmtCounterGet", "TestCase1.1", TC_PASS, "ok");
6495   }
6496 
6497   if ((TS_SUCCESS != TSMgmtFloatGet(CONFIG_PARAM_FLOAT_NAME, &fvalue)) || (fvalue != CONFIG_PARAM_FLOAT_VALUE)) {
6498     SDK_RPRINT(test, "TSMgmtFloatGet", "TestCase2", TC_FAIL, "can not get value of param %s", CONFIG_PARAM_FLOAT_NAME);
6499     err = 1;
6500   } else {
6501     SDK_RPRINT(test, "TSMgmtFloatGet", "TestCase1.2", TC_PASS, "ok");
6502   }
6503 
6504   if ((TSMgmtIntGet(CONFIG_PARAM_INT_NAME, &ivalue) != TS_SUCCESS) || (ivalue != CONFIG_PARAM_INT_VALUE)) {
6505     SDK_RPRINT(test, "TSMgmtIntGet", "TestCase1.3", TC_FAIL, "can not get value of param %s", CONFIG_PARAM_INT_NAME);
6506     err = 1;
6507   } else {
6508     SDK_RPRINT(test, "TSMgmtIntGet", "TestCase1.3", TC_PASS, "ok");
6509   }
6510 
6511   if (TS_SUCCESS != TSMgmtStringGet(CONFIG_PARAM_STRING_NAME, &svalue)) {
6512     SDK_RPRINT(test, "TSMgmtStringGet", "TestCase1.4", TC_FAIL, "can not get value of param %s", CONFIG_PARAM_STRING_NAME);
6513     err = 1;
6514   } else if (strcmp(svalue, CONFIG_PARAM_STRING_VALUE) != 0) {
6515     SDK_RPRINT(test, "TSMgmtStringGet", "TestCase1.4", TC_FAIL,
6516                R"(got incorrect value of param %s, should have been "%s", found "%s")", CONFIG_PARAM_STRING_NAME,
6517                CONFIG_PARAM_STRING_VALUE, svalue);
6518     err = 1;
6519   } else {
6520     SDK_RPRINT(test, "TSMgmtStringGet", "TestCase1.4", TC_PASS, "ok");
6521   }
6522 
6523   {
6524     TSRecordDataType result;
6525     auto ret = TSMgmtDataTypeGet(CONFIG_PARAM_STRING_NAME, &result);
6526     if (ret != TS_SUCCESS) {
6527       SDK_RPRINT(test, "TSMgmtDataTypeGet", "TestCase1.5", TC_FAIL, "can not get value of param %s", CONFIG_PARAM_STRING_NAME);
6528       err = 1;
6529     } else if (result != TSRecordDataType::TS_RECORDDATATYPE_STRING) {
6530       SDK_RPRINT(test, "TSMgmtDataTypeGet", "TestCase1.5", TC_FAIL, "can not get right type for %s - %d", CONFIG_PARAM_STRING_NAME,
6531                  result);
6532       err = 1;
6533     } else {
6534       SDK_RPRINT(test, "TSMgmtDataTypeGet", "TestCase1.5", TC_PASS, "ok");
6535     }
6536   }
6537 
6538   if (err) {
6539     *pstatus = REGRESSION_TEST_FAILED;
6540     return;
6541   }
6542 
6543   *pstatus = REGRESSION_TEST_PASSED;
6544   SDK_RPRINT(test, "TSMgmtGet", "TestCase1", TC_PASS, "ok");
6545   return;
6546 }
6547 
6548 //////////////////////////////////////////////
6549 //       SDK_API_TSConstant
6550 //
6551 // Unit Test for APIs: All TS_XXX constants
6552 //
6553 //////////////////////////////////////////////
6554 
6555 #define PRINT_DIFF(_x)                                                                                                 \
6556   {                                                                                                                    \
6557     if (_x - ORIG_##_x != 0) {                                                                                         \
6558       test_passed = false;                                                                                             \
6559       SDK_RPRINT(test, "##_x", "TestCase1", TC_FAIL, "%s:Original Value = %d; New Value = %d \n", #_x, _x, ORIG_##_x); \
6560     }                                                                                                                  \
6561   }
6562 
6563 enum ORIG_TSParseResult {
6564   ORIG_TS_PARSE_ERROR = -1,
6565   ORIG_TS_PARSE_DONE  = 0,
6566   ORIG_TS_PARSE_CONT  = 1,
6567 };
6568 
6569 enum ORIG_TSHttpType {
6570   ORIG_TS_HTTP_TYPE_UNKNOWN,
6571   ORIG_TS_HTTP_TYPE_REQUEST,
6572   ORIG_TS_HTTP_TYPE_RESPONSE,
6573 };
6574 
6575 enum ORIG_TSHttpStatus {
6576   ORIG_TS_HTTP_STATUS_NONE = 0,
6577 
6578   ORIG_TS_HTTP_STATUS_CONTINUE           = 100,
6579   ORIG_TS_HTTP_STATUS_SWITCHING_PROTOCOL = 101,
6580   ORIG_TS_HTTP_STATUS_EARLY_HINTS        = 103,
6581 
6582   ORIG_TS_HTTP_STATUS_OK                            = 200,
6583   ORIG_TS_HTTP_STATUS_CREATED                       = 201,
6584   ORIG_TS_HTTP_STATUS_ACCEPTED                      = 202,
6585   ORIG_TS_HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
6586   ORIG_TS_HTTP_STATUS_NO_CONTENT                    = 204,
6587   ORIG_TS_HTTP_STATUS_RESET_CONTENT                 = 205,
6588   ORIG_TS_HTTP_STATUS_PARTIAL_CONTENT               = 206,
6589 
6590   ORIG_TS_HTTP_STATUS_MULTIPLE_CHOICES  = 300,
6591   ORIG_TS_HTTP_STATUS_MOVED_PERMANENTLY = 301,
6592   ORIG_TS_HTTP_STATUS_MOVED_TEMPORARILY = 302,
6593   ORIG_TS_HTTP_STATUS_SEE_OTHER         = 303,
6594   ORIG_TS_HTTP_STATUS_NOT_MODIFIED      = 304,
6595   ORIG_TS_HTTP_STATUS_USE_PROXY         = 305,
6596 
6597   ORIG_TS_HTTP_STATUS_BAD_REQUEST                   = 400,
6598   ORIG_TS_HTTP_STATUS_UNAUTHORIZED                  = 401,
6599   ORIG_TS_HTTP_STATUS_PAYMENT_REQUIRED              = 402,
6600   ORIG_TS_HTTP_STATUS_FORBIDDEN                     = 403,
6601   ORIG_TS_HTTP_STATUS_NOT_FOUND                     = 404,
6602   ORIG_TS_HTTP_STATUS_METHOD_NOT_ALLOWED            = 405,
6603   ORIG_TS_HTTP_STATUS_NOT_ACCEPTABLE                = 406,
6604   ORIG_TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
6605   ORIG_TS_HTTP_STATUS_REQUEST_TIMEOUT               = 408,
6606   ORIG_TS_HTTP_STATUS_CONFLICT                      = 409,
6607   ORIG_TS_HTTP_STATUS_GONE                          = 410,
6608   ORIG_TS_HTTP_STATUS_LENGTH_REQUIRED               = 411,
6609   ORIG_TS_HTTP_STATUS_PRECONDITION_FAILED           = 412,
6610   ORIG_TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE      = 413,
6611   ORIG_TS_HTTP_STATUS_REQUEST_URI_TOO_LONG          = 414,
6612   ORIG_TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE        = 415,
6613 
6614   ORIG_TS_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
6615   ORIG_TS_HTTP_STATUS_NOT_IMPLEMENTED       = 501,
6616   ORIG_TS_HTTP_STATUS_BAD_GATEWAY           = 502,
6617   ORIG_TS_HTTP_STATUS_SERVICE_UNAVAILABLE   = 503,
6618   ORIG_TS_HTTP_STATUS_GATEWAY_TIMEOUT       = 504,
6619   ORIG_TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED = 505
6620 };
6621 
6622 enum ORIG_TSHttpHookID {
6623   ORIG_TS_HTTP_READ_REQUEST_HDR_HOOK,
6624   ORIG_TS_HTTP_OS_DNS_HOOK,
6625   ORIG_TS_HTTP_SEND_REQUEST_HDR_HOOK,
6626   ORIG_TS_HTTP_READ_CACHE_HDR_HOOK,
6627   ORIG_TS_HTTP_READ_RESPONSE_HDR_HOOK,
6628   ORIG_TS_HTTP_SEND_RESPONSE_HDR_HOOK,
6629   ORIG_TS_HTTP_REQUEST_TRANSFORM_HOOK,
6630   ORIG_TS_HTTP_RESPONSE_TRANSFORM_HOOK,
6631   ORIG_TS_HTTP_SELECT_ALT_HOOK,
6632   ORIG_TS_HTTP_TXN_START_HOOK,
6633   ORIG_TS_HTTP_TXN_CLOSE_HOOK,
6634   ORIG_TS_HTTP_SSN_START_HOOK,
6635   ORIG_TS_HTTP_SSN_CLOSE_HOOK,
6636   ORIG_TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK,
6637   ORIG_TS_HTTP_PRE_REMAP_HOOK,
6638   ORIG_TS_HTTP_POST_REMAP_HOOK,
6639   ORIG_TS_HTTP_RESPONSE_CLIENT_HOOK,
6640   ORIG_TS_SSL_FIRST_HOOK,
6641   ORIG_TS_VCONN_START_HOOK = ORIG_TS_SSL_FIRST_HOOK,
6642   ORIG_TS_VCONN_CLOSE_HOOK,
6643   ORIG_TS_SSL_CLIENT_HELLO_HOOK,
6644   ORIG_TS_SSL_SNI_HOOK,
6645   ORIG_TS_SSL_SERVERNAME_HOOK,
6646   ORIG_TS_SSL_VERIFY_SERVER_HOOK,
6647   ORIG_TS_SSL_VERIFY_CLIENT_HOOK,
6648   ORIG_TS_SSL_SESSION_HOOK,
6649   ORIG_TS_VCONN_OUTBOUND_START_HOOK,
6650   ORIG_TS_VCONN_OUTBOUND_CLOSE_HOOK,
6651   ORIG_TS_SSL_LAST_HOOK = ORIG_TS_VCONN_OUTBOUND_CLOSE_HOOK,
6652   ORIG_TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK,
6653   ORIG_TS_HTTP_LAST_HOOK
6654 };
6655 
6656 enum ORIG_TSEvent {
6657   ORIG_TS_EVENT_NONE      = 0,
6658   ORIG_TS_EVENT_IMMEDIATE = 1,
6659   ORIG_TS_EVENT_TIMEOUT   = 2,
6660   ORIG_TS_EVENT_ERROR     = 3,
6661   ORIG_TS_EVENT_CONTINUE  = 4,
6662 
6663   ORIG_TS_EVENT_VCONN_READ_READY     = 100,
6664   ORIG_TS_EVENT_VCONN_WRITE_READY    = 101,
6665   ORIG_TS_EVENT_VCONN_READ_COMPLETE  = 102,
6666   ORIG_TS_EVENT_VCONN_WRITE_COMPLETE = 103,
6667   ORIG_TS_EVENT_VCONN_EOS            = 104,
6668 
6669   ORIG_TS_EVENT_NET_CONNECT        = 200,
6670   ORIG_TS_EVENT_NET_CONNECT_FAILED = 201,
6671   ORIG_TS_EVENT_NET_ACCEPT         = 202,
6672   ORIG_TS_EVENT_NET_ACCEPT_FAILED  = 204,
6673 
6674   ORIG_TS_EVENT_HOST_LOOKUP = 500,
6675 
6676   ORIG_TS_EVENT_CACHE_OPEN_READ              = 1102,
6677   ORIG_TS_EVENT_CACHE_OPEN_READ_FAILED       = 1103,
6678   ORIG_TS_EVENT_CACHE_OPEN_WRITE             = 1108,
6679   ORIG_TS_EVENT_CACHE_OPEN_WRITE_FAILED      = 1109,
6680   ORIG_TS_EVENT_CACHE_REMOVE                 = 1112,
6681   ORIG_TS_EVENT_CACHE_REMOVE_FAILED          = 1113,
6682   ORIG_TS_EVENT_CACHE_SCAN                   = 1120,
6683   ORIG_TS_EVENT_CACHE_SCAN_FAILED            = 1121,
6684   ORIG_TS_EVENT_CACHE_SCAN_OBJECT            = 1122,
6685   ORIG_TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED = 1123,
6686   ORIG_TS_EVENT_CACHE_SCAN_OPERATION_FAILED  = 1124,
6687   ORIG_TS_EVENT_CACHE_SCAN_DONE              = 1125,
6688 
6689   ORIG_TS_EVENT_HTTP_CONTINUE              = 60000,
6690   ORIG_TS_EVENT_HTTP_ERROR                 = 60001,
6691   ORIG_TS_EVENT_HTTP_READ_REQUEST_HDR      = 60002,
6692   ORIG_TS_EVENT_HTTP_OS_DNS                = 60003,
6693   ORIG_TS_EVENT_HTTP_SEND_REQUEST_HDR      = 60004,
6694   ORIG_TS_EVENT_HTTP_READ_CACHE_HDR        = 60005,
6695   ORIG_TS_EVENT_HTTP_READ_RESPONSE_HDR     = 60006,
6696   ORIG_TS_EVENT_HTTP_SEND_RESPONSE_HDR     = 60007,
6697   ORIG_TS_EVENT_HTTP_REQUEST_TRANSFORM     = 60008,
6698   ORIG_TS_EVENT_HTTP_RESPONSE_TRANSFORM    = 60009,
6699   ORIG_TS_EVENT_HTTP_SELECT_ALT            = 60010,
6700   ORIG_TS_EVENT_HTTP_TXN_START             = 60011,
6701   ORIG_TS_EVENT_HTTP_TXN_CLOSE             = 60012,
6702   ORIG_TS_EVENT_HTTP_SSN_START             = 60013,
6703   ORIG_TS_EVENT_HTTP_SSN_CLOSE             = 60014,
6704   ORIG_TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE = 60015,
6705 
6706   ORIG_TS_EVENT_MGMT_UPDATE = 60300
6707 };
6708 
6709 enum ORIG_TSCacheLookupResult {
6710   ORIG_TS_CACHE_LOOKUP_MISS,
6711   ORIG_TS_CACHE_LOOKUP_HIT_STALE,
6712   ORIG_TS_CACHE_LOOKUP_HIT_FRESH,
6713 };
6714 
6715 enum ORIG_TSCacheDataType {
6716   ORIG_TS_CACHE_DATA_TYPE_NONE,
6717   ORIG_TS_CACHE_DATA_TYPE_HTTP,
6718   ORIG_TS_CACHE_DATA_TYPE_OTHER,
6719 };
6720 
6721 enum ORIG_TSCacheError {
6722   ORIG_TS_CACHE_ERROR_NO_DOC    = -20400,
6723   ORIG_TS_CACHE_ERROR_DOC_BUSY  = -20401,
6724   ORIG_TS_CACHE_ERROR_NOT_READY = -20407
6725 };
6726 
6727 enum ORIG_TSCacheScanResult {
6728   ORIG_TS_CACHE_SCAN_RESULT_DONE     = 0,
6729   ORIG_TS_CACHE_SCAN_RESULT_CONTINUE = 1,
6730   ORIG_TS_CACHE_SCAN_RESULT_DELETE   = 10,
6731   ORIG_TS_CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES,
6732   ORIG_TS_CACHE_SCAN_RESULT_UPDATE,
6733   ORIG_TS_CACHE_SCAN_RESULT_RETRY
6734 };
6735 
6736 enum ORIG_TSVConnCloseFlags {
6737   ORIG_TS_VC_CLOSE_ABORT  = -1,
6738   ORIG_TS_VC_CLOSE_NORMAL = 1,
6739 };
6740 
6741 enum ORIG_TSReturnCode {
6742   ORIG_TS_ERROR   = -1,
6743   ORIG_TS_SUCCESS = 0,
6744 };
6745 
REGRESSION_TEST(SDK_API_TSConstant)6746 REGRESSION_TEST(SDK_API_TSConstant)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
6747 {
6748   *pstatus         = REGRESSION_TEST_INPROGRESS;
6749   bool test_passed = true;
6750 
6751   PRINT_DIFF(TS_PARSE_ERROR);
6752   PRINT_DIFF(TS_PARSE_DONE);
6753   PRINT_DIFF(TS_PARSE_CONT);
6754 
6755   PRINT_DIFF(TS_HTTP_STATUS_NONE);
6756   PRINT_DIFF(TS_HTTP_STATUS_CONTINUE);
6757   PRINT_DIFF(TS_HTTP_STATUS_SWITCHING_PROTOCOL);
6758   PRINT_DIFF(TS_HTTP_STATUS_EARLY_HINTS);
6759 
6760   PRINT_DIFF(TS_HTTP_STATUS_OK);
6761   PRINT_DIFF(TS_HTTP_STATUS_CREATED);
6762 
6763   PRINT_DIFF(TS_HTTP_STATUS_ACCEPTED);
6764   PRINT_DIFF(TS_HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION);
6765   PRINT_DIFF(TS_HTTP_STATUS_NO_CONTENT);
6766   PRINT_DIFF(TS_HTTP_STATUS_RESET_CONTENT);
6767   PRINT_DIFF(TS_HTTP_STATUS_PARTIAL_CONTENT);
6768 
6769   PRINT_DIFF(TS_HTTP_STATUS_MULTIPLE_CHOICES);
6770   PRINT_DIFF(TS_HTTP_STATUS_MOVED_PERMANENTLY);
6771   PRINT_DIFF(TS_HTTP_STATUS_MOVED_TEMPORARILY);
6772   PRINT_DIFF(TS_HTTP_STATUS_SEE_OTHER);
6773   PRINT_DIFF(TS_HTTP_STATUS_NOT_MODIFIED);
6774   PRINT_DIFF(TS_HTTP_STATUS_USE_PROXY);
6775   PRINT_DIFF(TS_HTTP_STATUS_BAD_REQUEST);
6776   PRINT_DIFF(TS_HTTP_STATUS_UNAUTHORIZED);
6777   PRINT_DIFF(TS_HTTP_STATUS_FORBIDDEN);
6778   PRINT_DIFF(TS_HTTP_STATUS_NOT_FOUND);
6779   PRINT_DIFF(TS_HTTP_STATUS_METHOD_NOT_ALLOWED);
6780   PRINT_DIFF(TS_HTTP_STATUS_NOT_ACCEPTABLE);
6781   PRINT_DIFF(TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED);
6782   PRINT_DIFF(TS_HTTP_STATUS_REQUEST_TIMEOUT);
6783   PRINT_DIFF(TS_HTTP_STATUS_CONFLICT);
6784   PRINT_DIFF(TS_HTTP_STATUS_GONE);
6785   PRINT_DIFF(TS_HTTP_STATUS_PRECONDITION_FAILED);
6786   PRINT_DIFF(TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE);
6787   PRINT_DIFF(TS_HTTP_STATUS_REQUEST_URI_TOO_LONG);
6788   PRINT_DIFF(TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE);
6789   PRINT_DIFF(TS_HTTP_STATUS_INTERNAL_SERVER_ERROR);
6790   PRINT_DIFF(TS_HTTP_STATUS_NOT_IMPLEMENTED);
6791   PRINT_DIFF(TS_HTTP_STATUS_BAD_GATEWAY);
6792   PRINT_DIFF(TS_HTTP_STATUS_GATEWAY_TIMEOUT);
6793   PRINT_DIFF(TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED);
6794 
6795   PRINT_DIFF(TS_HTTP_READ_REQUEST_HDR_HOOK);
6796   PRINT_DIFF(TS_HTTP_OS_DNS_HOOK);
6797   PRINT_DIFF(TS_HTTP_SEND_REQUEST_HDR_HOOK);
6798   PRINT_DIFF(TS_HTTP_READ_RESPONSE_HDR_HOOK);
6799   PRINT_DIFF(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
6800   PRINT_DIFF(TS_HTTP_REQUEST_TRANSFORM_HOOK);
6801   PRINT_DIFF(TS_HTTP_RESPONSE_TRANSFORM_HOOK);
6802   PRINT_DIFF(TS_HTTP_SELECT_ALT_HOOK);
6803   PRINT_DIFF(TS_HTTP_TXN_START_HOOK);
6804   PRINT_DIFF(TS_HTTP_TXN_CLOSE_HOOK);
6805   PRINT_DIFF(TS_HTTP_SSN_START_HOOK);
6806   PRINT_DIFF(TS_HTTP_SSN_CLOSE_HOOK);
6807   PRINT_DIFF(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK);
6808   PRINT_DIFF(TS_HTTP_LAST_HOOK);
6809 
6810   PRINT_DIFF(TS_EVENT_NONE);
6811   PRINT_DIFF(TS_EVENT_IMMEDIATE);
6812   PRINT_DIFF(TS_EVENT_TIMEOUT);
6813   PRINT_DIFF(TS_EVENT_ERROR);
6814 
6815   PRINT_DIFF(TS_EVENT_CONTINUE);
6816   PRINT_DIFF(TS_EVENT_VCONN_READ_READY);
6817   PRINT_DIFF(TS_EVENT_VCONN_WRITE_READY);
6818   PRINT_DIFF(TS_EVENT_VCONN_READ_COMPLETE);
6819   PRINT_DIFF(TS_EVENT_VCONN_WRITE_COMPLETE);
6820   PRINT_DIFF(TS_EVENT_VCONN_EOS);
6821 
6822   PRINT_DIFF(TS_EVENT_NET_CONNECT);
6823   PRINT_DIFF(TS_EVENT_NET_CONNECT_FAILED);
6824   PRINT_DIFF(TS_EVENT_NET_ACCEPT);
6825   PRINT_DIFF(TS_EVENT_NET_ACCEPT_FAILED);
6826 
6827   PRINT_DIFF(TS_EVENT_HOST_LOOKUP);
6828 
6829   PRINT_DIFF(TS_EVENT_CACHE_OPEN_READ);
6830   PRINT_DIFF(TS_EVENT_CACHE_OPEN_READ_FAILED);
6831   PRINT_DIFF(TS_EVENT_CACHE_OPEN_WRITE);
6832   PRINT_DIFF(TS_EVENT_CACHE_OPEN_WRITE_FAILED);
6833   PRINT_DIFF(TS_EVENT_CACHE_REMOVE);
6834   PRINT_DIFF(TS_EVENT_CACHE_REMOVE_FAILED);
6835   PRINT_DIFF(TS_EVENT_CACHE_SCAN);
6836   PRINT_DIFF(TS_EVENT_CACHE_SCAN_FAILED);
6837   PRINT_DIFF(TS_EVENT_CACHE_SCAN_OBJECT);
6838   PRINT_DIFF(TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED);
6839   PRINT_DIFF(TS_EVENT_CACHE_SCAN_OPERATION_FAILED);
6840   PRINT_DIFF(TS_EVENT_CACHE_SCAN_DONE);
6841 
6842   PRINT_DIFF(TS_EVENT_HTTP_CONTINUE);
6843   PRINT_DIFF(TS_EVENT_HTTP_ERROR);
6844   PRINT_DIFF(TS_EVENT_HTTP_READ_REQUEST_HDR);
6845   PRINT_DIFF(TS_EVENT_HTTP_OS_DNS);
6846   PRINT_DIFF(TS_EVENT_HTTP_SEND_REQUEST_HDR);
6847   PRINT_DIFF(TS_EVENT_HTTP_READ_CACHE_HDR);
6848   PRINT_DIFF(TS_EVENT_HTTP_READ_RESPONSE_HDR);
6849   PRINT_DIFF(TS_EVENT_HTTP_SEND_RESPONSE_HDR);
6850   PRINT_DIFF(TS_EVENT_HTTP_REQUEST_TRANSFORM);
6851   PRINT_DIFF(TS_EVENT_HTTP_RESPONSE_TRANSFORM);
6852   PRINT_DIFF(TS_EVENT_HTTP_SELECT_ALT);
6853   PRINT_DIFF(TS_EVENT_HTTP_TXN_START);
6854   PRINT_DIFF(TS_EVENT_HTTP_TXN_CLOSE);
6855   PRINT_DIFF(TS_EVENT_HTTP_SSN_START);
6856   PRINT_DIFF(TS_EVENT_HTTP_SSN_CLOSE);
6857   PRINT_DIFF(TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE);
6858 
6859   PRINT_DIFF(TS_EVENT_MGMT_UPDATE);
6860 
6861   PRINT_DIFF(TS_CACHE_LOOKUP_MISS);
6862   PRINT_DIFF(TS_CACHE_LOOKUP_HIT_STALE);
6863   PRINT_DIFF(TS_CACHE_LOOKUP_HIT_FRESH);
6864 
6865   PRINT_DIFF(TS_CACHE_DATA_TYPE_NONE);
6866   PRINT_DIFF(TS_CACHE_DATA_TYPE_HTTP);
6867   PRINT_DIFF(TS_CACHE_DATA_TYPE_OTHER);
6868 
6869   PRINT_DIFF(TS_CACHE_ERROR_NO_DOC);
6870   PRINT_DIFF(TS_CACHE_ERROR_DOC_BUSY);
6871   PRINT_DIFF(TS_CACHE_ERROR_NOT_READY);
6872 
6873   PRINT_DIFF(TS_CACHE_SCAN_RESULT_DONE);
6874   PRINT_DIFF(TS_CACHE_SCAN_RESULT_CONTINUE);
6875   PRINT_DIFF(TS_CACHE_SCAN_RESULT_DELETE);
6876   PRINT_DIFF(TS_CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES);
6877   PRINT_DIFF(TS_CACHE_SCAN_RESULT_UPDATE);
6878   PRINT_DIFF(TS_CACHE_SCAN_RESULT_RETRY);
6879 
6880   PRINT_DIFF(TS_VC_CLOSE_ABORT);
6881   PRINT_DIFF(TS_VC_CLOSE_NORMAL);
6882 
6883   PRINT_DIFF(TS_ERROR);
6884   PRINT_DIFF(TS_SUCCESS);
6885 
6886   if (test_passed) {
6887     *pstatus = REGRESSION_TEST_PASSED;
6888   } else {
6889     *pstatus = REGRESSION_TEST_FAILED;
6890   }
6891 }
6892 
6893 //////////////////////////////////////////////
6894 //       SDK_API_TSHttpSsn
6895 //
6896 // Unit Test for API: TSHttpSsnHookAdd
6897 //                    TSHttpSsnReenable
6898 //                    TSHttpTxnHookAdd
6899 //                    TSHttpTxnErrorBodySet
6900 //                    TSHttpTxnParentProxyGet
6901 //                    TSHttpTxnParentProxySet
6902 //////////////////////////////////////////////
6903 
6904 struct ContData {
6905   RegressionTest *test;
6906   int *pstatus;
6907   SocketServer *os;
6908   ClientTxn *browser;
6909   TSHttpSsn ssnp;
6910   int test_passed_ssn_hook_add;
6911   int test_passed_ssn_reenable;
6912   int test_passed_txn_ssn_get;
6913   int test_passed_txn_hook_add;
6914   int test_passed_txn_error_body_set;
6915   bool test_passed_Parent_Proxy;
6916   int magic;
6917 };
6918 
6919 static int
checkHttpTxnParentProxy(ContData * data,TSHttpTxn txnp)6920 checkHttpTxnParentProxy(ContData *data, TSHttpTxn txnp)
6921 {
6922   const char *hostname    = "txnpp.example.com";
6923   int port                = 10180;
6924   const char *hostnameget = nullptr;
6925   int portget             = 0;
6926 
6927   TSHttpTxnParentProxySet(txnp, const_cast<char *>(hostname), port);
6928   if (TSHttpTxnParentProxyGet(txnp, &hostnameget, &portget) != TS_SUCCESS) {
6929     SDK_RPRINT(data->test, "TSHttpTxnParentProxySet", "TestCase1", TC_FAIL, "TSHttpTxnParentProxyGet doesn't return TS_SUCCESS");
6930     SDK_RPRINT(data->test, "TSHttpTxnParentProxyGet", "TestCase1", TC_FAIL, "TSHttpTxnParentProxyGet doesn't return TS_SUCCESS");
6931     return TS_EVENT_CONTINUE;
6932   }
6933 
6934   if ((strcmp(hostname, hostnameget) == 0) && (port == portget)) {
6935     SDK_RPRINT(data->test, "TSHttpTxnParentProxySet", "TestCase1", TC_PASS, "ok");
6936     SDK_RPRINT(data->test, "TSHttpTxnParentProxyGet", "TestCase1", TC_PASS, "ok");
6937     data->test_passed_Parent_Proxy = true;
6938   } else {
6939     SDK_RPRINT(data->test, "TSHttpTxnParentProxySet", "TestCase1", TC_FAIL, "Value's Mismatch");
6940     SDK_RPRINT(data->test, "TSHttpTxnParentProxyGet", "TestCase1", TC_FAIL, "Value's Mismatch");
6941   }
6942 
6943   return TS_EVENT_CONTINUE;
6944 }
6945 
6946 static int
ssn_handler(TSCont contp,TSEvent event,void * edata)6947 ssn_handler(TSCont contp, TSEvent event, void *edata)
6948 {
6949   TSHttpTxn txnp = nullptr;
6950   ContData *data = nullptr;
6951   data           = static_cast<ContData *>(TSContDataGet(contp));
6952   if (data == nullptr) {
6953     switch (event) {
6954     case TS_EVENT_HTTP_SSN_START:
6955       TSHttpSsnReenable(static_cast<TSHttpSsn>(edata), TS_EVENT_HTTP_CONTINUE);
6956       break;
6957     case TS_EVENT_IMMEDIATE:
6958     case TS_EVENT_TIMEOUT:
6959       break;
6960     case TS_EVENT_HTTP_TXN_START:
6961     default:
6962       TSHttpTxnReenable(static_cast<TSHttpTxn>(edata), TS_EVENT_HTTP_CONTINUE);
6963       break;
6964     }
6965     return 0;
6966   }
6967 
6968   switch (event) {
6969   case TS_EVENT_HTTP_SSN_START:
6970     data->ssnp = static_cast<TSHttpSsn>(edata);
6971     TSHttpSsnHookAdd(data->ssnp, TS_HTTP_TXN_START_HOOK, contp);
6972     TSHttpSsnReenable(data->ssnp, TS_EVENT_HTTP_CONTINUE);
6973     break;
6974 
6975   case TS_EVENT_HTTP_TXN_START:
6976     TSSkipRemappingSet(static_cast<TSHttpTxn>(edata), 1);
6977     SDK_RPRINT(data->test, "TSHttpSsnReenable", "TestCase", TC_PASS, "ok");
6978     data->test_passed_ssn_reenable++;
6979     {
6980       txnp           = static_cast<TSHttpTxn>(edata);
6981       TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp);
6982       if (ssnp != data->ssnp) {
6983         SDK_RPRINT(data->test, "TSHttpSsnHookAdd", "TestCase", TC_FAIL, "Value's mismatch");
6984         data->test_passed_ssn_hook_add--;
6985         SDK_RPRINT(data->test, "TSHttpTxnSsnGet", "TestCase", TC_FAIL, "Session doesn't match");
6986         data->test_passed_txn_ssn_get--;
6987       } else {
6988         SDK_RPRINT(data->test, "TSHttpSsnHookAdd", "TestCase1", TC_PASS, "ok");
6989         data->test_passed_ssn_hook_add++;
6990         SDK_RPRINT(data->test, "TSHttpTxnSsnGet", "TestCase1", TC_PASS, "ok");
6991         data->test_passed_txn_ssn_get++;
6992       }
6993       TSHttpTxnHookAdd(txnp, TS_HTTP_OS_DNS_HOOK, contp);
6994       TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
6995     }
6996     break;
6997 
6998   case TS_EVENT_HTTP_OS_DNS:
6999     SDK_RPRINT(data->test, "TSHttpTxnHookAdd", "TestCase1", TC_PASS, "ok");
7000     data->test_passed_txn_hook_add++;
7001     txnp = static_cast<TSHttpTxn>(edata);
7002 
7003     TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
7004     checkHttpTxnParentProxy(data, txnp);
7005 
7006     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
7007     break;
7008 
7009   case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
7010     SDK_RPRINT(data->test, "TSHttpTxnHookAdd", "TestCase2", TC_PASS, "ok");
7011     data->test_passed_txn_hook_add++;
7012     txnp = static_cast<TSHttpTxn>(edata);
7013     if (true) {
7014       char *temp = TSstrdup(ERROR_BODY);
7015       TSHttpTxnErrorBodySet(txnp, temp, strlen(temp), nullptr);
7016     }
7017     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7018     break;
7019 
7020   case TS_EVENT_IMMEDIATE:
7021   case TS_EVENT_TIMEOUT:
7022     /* Browser still waiting the response ? */
7023     if (data->browser->status == REQUEST_INPROGRESS) {
7024       TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7025     }
7026     /* Browser got the response. test is over. clean up */
7027     else {
7028       /* Check if browser response body is the one we expected */
7029       char *temp = data->browser->response;
7030       temp       = strstr(temp, "\r\n\r\n");
7031       if (temp != nullptr) {
7032         temp += strlen("\r\n\r\n");
7033         if ((temp[0] == '\0') || (strncmp(temp, "\r\n\r\n", 4) == 0)) {
7034           SDK_RPRINT(data->test, "TSHttpTxnErrorBodySet", "TestCase1", TC_FAIL, "No Error Body found");
7035           data->test_passed_txn_error_body_set--;
7036         }
7037         if (strncmp(temp, ERROR_BODY, strlen(ERROR_BODY)) == 0) {
7038           SDK_RPRINT(data->test, "TSHttpTxnErrorBodySet", "TestCase1", TC_PASS, "ok");
7039           data->test_passed_txn_error_body_set++;
7040         }
7041       } else {
7042         SDK_RPRINT(data->test, "TSHttpTxnErrorBodySet", "TestCase1", TC_FAIL, "strstr returns NULL. Didn't find end of headers.");
7043         data->test_passed_txn_error_body_set--;
7044       }
7045 
7046       /* Note: response is available using test->browser->response pointer */
7047       if ((data->browser->status == REQUEST_SUCCESS) && (data->test_passed_ssn_hook_add == 1) &&
7048           (data->test_passed_ssn_reenable == 1) && (data->test_passed_txn_ssn_get == 1) && (data->test_passed_txn_hook_add == 2) &&
7049           (data->test_passed_txn_error_body_set == 1) && (data->test_passed_Parent_Proxy == true)) {
7050         *(data->pstatus) = REGRESSION_TEST_PASSED;
7051       } else {
7052         *(data->pstatus) = REGRESSION_TEST_FAILED;
7053       }
7054 
7055       // transaction is over. clean up.
7056       synclient_txn_delete(data->browser);
7057       /* Don't need it as didn't initialize the server
7058          synserver_delete(data->os);
7059        */
7060       data->os    = nullptr;
7061       data->magic = MAGIC_DEAD;
7062       TSfree(data);
7063       TSContDataSet(contp, nullptr);
7064     }
7065     break;
7066 
7067   default:
7068     *(data->pstatus) = REGRESSION_TEST_FAILED;
7069     SDK_RPRINT(data->test, "TSHttpSsn", "TestCase1", TC_FAIL, "Unexpected event %d", event);
7070     break;
7071   }
7072   return 0;
7073 }
7074 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpSsn)7075 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpSsn)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
7076 {
7077   *pstatus = REGRESSION_TEST_INPROGRESS;
7078 
7079   TSCont cont = TSContCreate(ssn_handler, TSMutexCreate());
7080   if (cont == nullptr) {
7081     SDK_RPRINT(test, "TSHttpSsn", "TestCase1", TC_FAIL, "Unable to create Continuation.");
7082     *pstatus = REGRESSION_TEST_FAILED;
7083     return;
7084   }
7085 
7086   ContData *socktest                       = static_cast<ContData *>(TSmalloc(sizeof(ContData)));
7087   socktest->test                           = test;
7088   socktest->pstatus                        = pstatus;
7089   socktest->test_passed_ssn_hook_add       = 0;
7090   socktest->test_passed_ssn_reenable       = 0;
7091   socktest->test_passed_txn_ssn_get        = 0;
7092   socktest->test_passed_txn_hook_add       = 0;
7093   socktest->test_passed_txn_error_body_set = 0;
7094   socktest->test_passed_Parent_Proxy       = false;
7095   socktest->magic                          = MAGIC_ALIVE;
7096   TSContDataSet(cont, socktest);
7097 
7098   /* Register to HTTP hooks that are called in case of a cache MISS */
7099   TSHttpHookAdd(TS_HTTP_SSN_START_HOOK, cont);
7100 
7101   /* Create a client transaction */
7102   socktest->browser = synclient_txn_create();
7103   char *request     = generate_request(3); // response is expected to be error case
7104   synclient_txn_send_request(socktest->browser, request);
7105   TSfree(request);
7106 
7107   /* Wait until transaction is done */
7108   if (socktest->browser->status == REQUEST_INPROGRESS) {
7109     TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
7110   }
7111 
7112   return;
7113 }
7114 
7115 struct ParentTest {
ParentTestParentTest7116   ParentTest(RegressionTest *test, int *pstatus)
7117   {
7118     ink_zero(*this);
7119     this->regtest    = test;
7120     this->pstatus    = pstatus;
7121     this->magic      = MAGIC_ALIVE;
7122     this->configured = false;
7123     this->browser    = synclient_txn_create();
7124   }
7125 
~ParentTestParentTest7126   ~ParentTest()
7127   {
7128     synclient_txn_close(this->browser);
7129     synclient_txn_delete(this->browser);
7130     synserver_delete(this->os);
7131     this->os    = nullptr;
7132     this->magic = MAGIC_DEAD;
7133   }
7134 
7135   bool
parent_routing_enabledParentTest7136   parent_routing_enabled() const
7137   {
7138     RecBool enabled = false;
7139 
7140     ParentConfigParams *params = ParentConfig::acquire();
7141     enabled                    = params->policy.ParentEnable;
7142     ParentConfig::release(params);
7143 
7144     return enabled;
7145   }
7146 
7147   RegressionTest *regtest;
7148   int *pstatus;
7149   bool configured;
7150 
7151   const char *testcase;
7152   SocketServer *os;
7153   ClientTxn *browser;
7154   TSEventFunc handler;
7155 
7156   unsigned int magic;
7157 };
7158 
7159 static int
parent_proxy_success(TSCont contp,TSEvent event,void * edata)7160 parent_proxy_success(TSCont contp, TSEvent event, void *edata)
7161 {
7162   ParentTest *ptest = static_cast<ParentTest *>(TSContDataGet(contp));
7163   TSHttpTxn txnp    = static_cast<TSHttpTxn>(edata);
7164 
7165   int expected;
7166   int received;
7167   int status;
7168 
7169   switch (event) {
7170   case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
7171     expected = get_request_id(txnp);
7172     received = get_response_id(txnp);
7173 
7174     if (expected != received) {
7175       status = REGRESSION_TEST_FAILED;
7176       SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_FAIL, "Expected response ID %d, received %d", expected,
7177                  received);
7178     } else {
7179       status = REGRESSION_TEST_PASSED;
7180       SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_PASS, "Received expected response ID %d", expected);
7181     }
7182     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7183     return status;
7184 
7185   default:
7186     SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", ptest->testcase, TC_FAIL, "Unexpected event %d", event);
7187     return REGRESSION_TEST_FAILED;
7188   }
7189 }
7190 
7191 static int
parent_proxy_fail(TSCont contp,TSEvent event,void * edata)7192 parent_proxy_fail(TSCont contp, TSEvent event, void *edata)
7193 {
7194   ParentTest *ptest = static_cast<ParentTest *>(TSContDataGet(contp));
7195   TSHttpTxn txnp    = static_cast<TSHttpTxn>(edata);
7196 
7197   TSMBuffer mbuf;
7198   TSMLoc hdr;
7199   TSHttpStatus expected = TS_HTTP_STATUS_BAD_GATEWAY;
7200   TSHttpStatus received;
7201   int status;
7202 
7203   switch (event) {
7204   case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
7205     ink_release_assert(TSHttpTxnClientRespGet(txnp, &mbuf, &hdr) == TS_SUCCESS);
7206     received = TSHttpHdrStatusGet(mbuf, hdr);
7207 
7208     if (expected != received) {
7209       status = REGRESSION_TEST_FAILED;
7210       SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_FAIL, "Expected response status %d, received %d",
7211                  expected, received);
7212     } else {
7213       status = REGRESSION_TEST_PASSED;
7214       SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_PASS, "Received expected response status %d", expected);
7215     }
7216 
7217     TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdr);
7218     return status;
7219 
7220   default:
7221     SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", ptest->testcase, TC_FAIL, "Unexpected event %d", event);
7222     return REGRESSION_TEST_FAILED;
7223   }
7224 }
7225 
7226 static int
parent_proxy_handler(TSCont contp,TSEvent event,void * edata)7227 parent_proxy_handler(TSCont contp, TSEvent event, void *edata)
7228 {
7229   ParentTest *ptest = nullptr;
7230 
7231   CHECK_SPURIOUS_EVENT(contp, event, edata);
7232   ptest = static_cast<ParentTest *>(TSContDataGet(contp));
7233   ink_release_assert(ptest);
7234 
7235   TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
7236 
7237   switch (event) {
7238   case TS_EVENT_HTTP_READ_REQUEST_HDR:
7239     rprintf(ptest->regtest, "setting synserver parent proxy to %s:%d\n", "127.0.0.1", SYNSERVER_LISTEN_PORT);
7240 
7241     // Since we chose a request format with a hostname of trafficserver.apache.org, it won't get
7242     // sent to the synserver unless we set a parent proxy.
7243     TSHttpTxnParentProxySet(txnp, "127.0.0.1", SYNSERVER_LISTEN_PORT);
7244 
7245     TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
7246     TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, contp);
7247 
7248     TSSkipRemappingSet(txnp, 1);
7249     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7250     break;
7251 
7252   case TS_EVENT_TIMEOUT:
7253     if (*(ptest->pstatus) == REGRESSION_TEST_INPROGRESS) {
7254       if (ptest->configured) {
7255         // If we are still in progress, reschedule.
7256         rprintf(ptest->regtest, "waiting for response\n");
7257         TSContScheduleOnPool(contp, 100, TS_THREAD_POOL_NET);
7258         break;
7259       }
7260 
7261       if (!ptest->parent_routing_enabled()) {
7262         rprintf(ptest->regtest, "waiting for configuration\n");
7263         TSContScheduleOnPool(contp, 100, TS_THREAD_POOL_NET);
7264         break;
7265       }
7266 
7267       // Now that the configuration is applied, it is safe to create a request.
7268       // HTTP_REQUEST_FORMAT11 is a hostname with a no-cache response, so
7269       // we will need to set the parent to the synserver to get a
7270       // response.
7271       char *request = generate_request(11);
7272       synclient_txn_send_request(ptest->browser, request);
7273       TSfree(request);
7274 
7275       ptest->configured = true;
7276 
7277     } else {
7278       // Otherwise the test completed so clean up.
7279       TSContDataSet(contp, nullptr);
7280       delete ptest;
7281     }
7282     break;
7283 
7284   case TS_EVENT_HTTP_TXN_CLOSE:
7285     // We expected to pass or fail reading the response header. At this point we must have failed.
7286     if (*(ptest->pstatus) == REGRESSION_TEST_INPROGRESS) {
7287       *(ptest->pstatus) = REGRESSION_TEST_FAILED;
7288       SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", ptest->testcase, TC_FAIL, "Failed on txn close");
7289     }
7290     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7291     break;
7292 
7293   default:
7294 
7295   {
7296     int status = ptest->handler(contp, event, edata);
7297     if (status != REGRESSION_TEST_INPROGRESS) {
7298       int *pstatus = ptest->pstatus;
7299 
7300       TSContDataSet(contp, nullptr);
7301       delete ptest;
7302 
7303       *pstatus = status;
7304     }
7305   }
7306   }
7307 
7308   return TS_EVENT_NONE;
7309 }
7310 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpParentProxySet_Fail)7311 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpParentProxySet_Fail)(RegressionTest *test, int level, int *pstatus)
7312 {
7313   *pstatus = REGRESSION_TEST_INPROGRESS;
7314 
7315   if (level < REGRESSION_TEST_EXTENDED) {
7316     *pstatus = REGRESSION_TEST_NOT_RUN;
7317     return;
7318   }
7319 
7320   TSCont cont = TSContCreate(parent_proxy_handler, TSMutexCreate());
7321   if (cont == nullptr) {
7322     SDK_RPRINT(test, "TSHttpTxnParentProxySet", "FailCase", TC_FAIL, "Unable to create continuation");
7323     *pstatus = REGRESSION_TEST_FAILED;
7324     return;
7325   }
7326 
7327   ParentTest *ptest = new ParentTest(test, pstatus);
7328 
7329   ptest->testcase = "FailCase";
7330   ptest->handler  = parent_proxy_fail;
7331   TSContDataSet(cont, ptest);
7332 
7333   /* Hook read request headers, since that is the earliest reasonable place to set the parent proxy. */
7334   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont);
7335 
7336   /* Create a new synthetic server */
7337   ptest->os = synserver_create(SYNSERVER_LISTEN_PORT, TSContCreate(synserver_vc_refuse, TSMutexCreate()));
7338   synserver_start(ptest->os);
7339 
7340   TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
7341 }
7342 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpParentProxySet_Success)7343 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpParentProxySet_Success)(RegressionTest *test, int level, int *pstatus)
7344 {
7345   *pstatus = REGRESSION_TEST_INPROGRESS;
7346 
7347   if (level < REGRESSION_TEST_EXTENDED) {
7348     *pstatus = REGRESSION_TEST_NOT_RUN;
7349     return;
7350   }
7351 
7352   TSCont cont = TSContCreate(parent_proxy_handler, TSMutexCreate());
7353   if (cont == nullptr) {
7354     SDK_RPRINT(test, "TSHttpTxnParentProxySet", "SuccessCase", TC_FAIL, "Unable to create continuation");
7355     *pstatus = REGRESSION_TEST_FAILED;
7356     return;
7357   }
7358 
7359   ParentTest *ptest = new ParentTest(test, pstatus);
7360 
7361   ptest->testcase = "SuccessCase";
7362   ptest->handler  = parent_proxy_success;
7363   TSContDataSet(cont, ptest);
7364 
7365   /* Hook read request headers, since that is the earliest reasonable place to set the parent proxy. */
7366   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont);
7367 
7368   /* Create a new synthetic server */
7369   ptest->os = synserver_create(SYNSERVER_LISTEN_PORT, TSContCreate(synserver_vc_accept, TSMutexCreate()));
7370   synserver_start(ptest->os);
7371 
7372   TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
7373 }
7374 
7375 /////////////////////////////////////////////////////
7376 //       SDK_API_TSHttpTxnCache
7377 //
7378 // Unit Test for API: TSHttpTxnCachedReqGet
7379 //                    TSHttpTxnCachedRespGet
7380 //                    TSHttpTxnCacheLookupStatusGet
7381 /////////////////////////////////////////////////////
7382 
7383 struct CacheTestData {
7384   RegressionTest *test;
7385   int *pstatus;
7386   SocketServer *os;
7387   ClientTxn *browser1;
7388   ClientTxn *browser2;
7389   char *request;
7390   bool test_passed_txn_cached_req_get;
7391   bool test_passed_txn_cached_resp_get;
7392   bool test_passed_txn_cache_lookup_status;
7393   bool first_time;
7394   int magic;
7395 };
7396 
7397 static int
cache_hook_handler(TSCont contp,TSEvent event,void * edata)7398 cache_hook_handler(TSCont contp, TSEvent event, void *edata)
7399 {
7400   TSHttpTxn txnp      = nullptr;
7401   CacheTestData *data = nullptr;
7402 
7403   CHECK_SPURIOUS_EVENT(contp, event, edata);
7404   data = static_cast<CacheTestData *>(TSContDataGet(contp));
7405 
7406   switch (event) {
7407   case TS_EVENT_HTTP_READ_REQUEST_HDR:
7408     txnp = static_cast<TSHttpTxn>(edata);
7409     TSSkipRemappingSet(txnp, 1);
7410     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7411     break;
7412 
7413   case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE: {
7414     int lookup_status;
7415     if (data->first_time == true) {
7416       txnp = static_cast<TSHttpTxn>(edata);
7417       if (TSHttpTxnCacheLookupStatusGet(txnp, &lookup_status) != TS_SUCCESS) {
7418         SDK_RPRINT(data->test, "TSHttpTxnCacheLookupStatusGet", "TestCase1", TC_FAIL,
7419                    "TSHttpTxnCacheLookupStatus doesn't return TS_SUCCESS");
7420       } else {
7421         if (lookup_status == TS_CACHE_LOOKUP_MISS) {
7422           SDK_RPRINT(data->test, "TSHttpTxnCacheLookupStatusGet", "TestCase1", TC_PASS, "ok");
7423           data->test_passed_txn_cache_lookup_status = true;
7424         } else {
7425           SDK_RPRINT(data->test, "TSHttpTxnCacheLookupStatusGet", "TestCase1", TC_FAIL,
7426                      "Incorrect Value returned by TSHttpTxnCacheLookupStatusGet");
7427         }
7428       }
7429     } else {
7430       txnp = static_cast<TSHttpTxn>(edata);
7431       if (TSHttpTxnCacheLookupStatusGet(txnp, &lookup_status) != TS_SUCCESS) {
7432         SDK_RPRINT(data->test, "TSHttpTxnCacheLookupStatusGet", "TestCase2", TC_FAIL,
7433                    "TSHttpTxnCacheLookupStatus doesn't return TS_SUCCESS");
7434         data->test_passed_txn_cache_lookup_status = false;
7435       } else {
7436         if (lookup_status == TS_CACHE_LOOKUP_HIT_FRESH) {
7437           SDK_RPRINT(data->test, "TSHttpTxnCacheLookupStatusGet", "TestCase2", TC_PASS, "ok");
7438         } else {
7439           SDK_RPRINT(data->test, "TSHttpTxnCacheLookupStatusGet", "TestCase2", TC_FAIL,
7440                      "Incorrect Value returned by TSHttpTxnCacheLookupStatusGet");
7441           data->test_passed_txn_cache_lookup_status = false;
7442         }
7443       }
7444     }
7445     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7446   } break;
7447   case TS_EVENT_HTTP_READ_CACHE_HDR: {
7448     TSMBuffer reqbuf;
7449     TSMBuffer respbuf;
7450 
7451     TSMLoc reqhdr;
7452     TSMLoc resphdr;
7453 
7454     txnp = static_cast<TSHttpTxn>(edata);
7455 
7456     if (TSHttpTxnCachedReqGet(txnp, &reqbuf, &reqhdr) != TS_SUCCESS) {
7457       SDK_RPRINT(data->test, "TSHttpTxnCachedReqGet", "TestCase1", TC_FAIL, "TSHttpTxnCachedReqGet returns 0");
7458     } else {
7459       if ((reqbuf == reinterpret_cast<TSMBuffer>(((HttpSM *)txnp)->t_state.cache_req_hdr_heap_handle)) &&
7460           (reqhdr == reinterpret_cast<TSMLoc>((((HttpSM *)txnp)->t_state.cache_info.object_read->request_get())->m_http))) {
7461         SDK_RPRINT(data->test, "TSHttpTxnCachedReqGet", "TestCase1", TC_PASS, "ok");
7462         data->test_passed_txn_cached_req_get = true;
7463       } else {
7464         SDK_RPRINT(data->test, "TSHttpTxnCachedReqGet", "TestCase1", TC_FAIL, "Value's Mismatch");
7465       }
7466     }
7467 
7468     if (TSHttpTxnCachedRespGet(txnp, &respbuf, &resphdr) != TS_SUCCESS) {
7469       SDK_RPRINT(data->test, "TSHttpTxnCachedRespGet", "TestCase1", TC_FAIL, "TSHttpTxnCachedRespGet returns 0");
7470     } else {
7471       if ((respbuf == reinterpret_cast<TSMBuffer>(((HttpSM *)txnp)->t_state.cache_resp_hdr_heap_handle)) &&
7472           (resphdr == reinterpret_cast<TSMLoc>((((HttpSM *)txnp)->t_state.cache_info.object_read->response_get())->m_http))) {
7473         SDK_RPRINT(data->test, "TSHttpTxnCachedRespGet", "TestCase1", TC_PASS, "ok");
7474         data->test_passed_txn_cached_resp_get = true;
7475       } else {
7476         SDK_RPRINT(data->test, "TSHttpTxnCachedRespGet", "TestCase1", TC_FAIL, "Value's Mismatch");
7477       }
7478     }
7479 
7480     if ((TSHandleMLocRelease(reqbuf, TS_NULL_MLOC, reqhdr) != TS_SUCCESS) ||
7481         (TSHandleMLocRelease(respbuf, TS_NULL_MLOC, resphdr) != TS_SUCCESS)) {
7482       SDK_RPRINT(data->test, "TSHttpTxnCache", "", TC_FAIL, "Unable to release handle to headers.");
7483     }
7484 
7485     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7486   }
7487 
7488   break;
7489 
7490   case TS_EVENT_IMMEDIATE:
7491   case TS_EVENT_TIMEOUT:
7492     /* Browser still waiting the response ? */
7493     if (data->first_time == true) {
7494       if (data->browser1->status == REQUEST_INPROGRESS) {
7495         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7496         return 0;
7497       }
7498     } else {
7499       if (data->browser2->status == REQUEST_INPROGRESS) {
7500         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7501         return 0;
7502       }
7503     }
7504 
7505     /* Browser got the response. test is over. clean up */
7506     {
7507       /* If this is the first time, then the response is in cache and we should make */
7508       /* another request to get cache hit */
7509       if (data->first_time == true) {
7510         data->first_time = false;
7511         /* Kill the origin server */
7512         synserver_delete(data->os);
7513         data->os = nullptr;
7514 
7515         /* Send another similar client request */
7516         synclient_txn_send_request(data->browser2, data->request);
7517         ink_assert(REQUEST_INPROGRESS == data->browser2->status);
7518         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7519         return 0;
7520       }
7521 
7522       /* Note: response is available using test->browser->response pointer */
7523       if ((data->browser1->status == REQUEST_SUCCESS) && (data->browser2->status == REQUEST_SUCCESS) &&
7524           (data->test_passed_txn_cached_req_get == true) && (data->test_passed_txn_cached_resp_get == true) &&
7525           (data->test_passed_txn_cache_lookup_status == true)) {
7526         *(data->pstatus) = REGRESSION_TEST_PASSED;
7527       } else {
7528         *(data->pstatus) = REGRESSION_TEST_FAILED;
7529       }
7530 
7531       // transaction is over. clean up.
7532       synclient_txn_delete(data->browser1);
7533       synclient_txn_delete(data->browser2);
7534 
7535       data->magic = MAGIC_DEAD;
7536       TSfree(data->request);
7537       TSfree(data);
7538       TSContDataSet(contp, nullptr);
7539     }
7540     break;
7541 
7542   default:
7543     *(data->pstatus) = REGRESSION_TEST_FAILED;
7544     SDK_RPRINT(data->test, "TSHttpTxnCache", "TestCase1", TC_FAIL, "Unexpected event %d", event);
7545     break;
7546   }
7547   return 0;
7548 }
7549 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpTxnCache)7550 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpTxnCache)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
7551 {
7552   *pstatus = REGRESSION_TEST_INPROGRESS;
7553 
7554   TSCont cont = TSContCreate(cache_hook_handler, TSMutexCreate());
7555 
7556   if (cont == nullptr) {
7557     SDK_RPRINT(test, "TSHttpSsn", "TestCase1", TC_FAIL, "Unable to create Continuation.");
7558     *pstatus = REGRESSION_TEST_FAILED;
7559     return;
7560   }
7561 
7562   CacheTestData *socktest                   = static_cast<CacheTestData *>(TSmalloc(sizeof(CacheTestData)));
7563   socktest->test                            = test;
7564   socktest->pstatus                         = pstatus;
7565   socktest->test_passed_txn_cached_req_get  = false;
7566   socktest->test_passed_txn_cached_resp_get = false;
7567   socktest->first_time                      = true;
7568   socktest->magic                           = MAGIC_ALIVE;
7569   TSContDataSet(cont, socktest);
7570 
7571   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont);
7572   /* Register to HTTP hooks that are called in case of a cache MISS */
7573   TSHttpHookAdd(TS_HTTP_READ_CACHE_HDR_HOOK, cont);
7574   TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont);
7575 
7576   /* Create a new synthetic server */
7577   socktest->os = synserver_create(SYNSERVER_LISTEN_PORT);
7578   synserver_start(socktest->os);
7579 
7580   /* Create a client transaction */
7581   socktest->browser1 = synclient_txn_create();
7582   socktest->browser2 = synclient_txn_create();
7583   socktest->request  = generate_request(2);
7584   synclient_txn_send_request(socktest->browser1, socktest->request);
7585 
7586   /* Wait until transaction is done */
7587   TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
7588 
7589   return;
7590 }
7591 
7592 ///////////////////////////////////////////////////////
7593 //       SDK_API_TSHttpTxnTransform
7594 //
7595 // Unit Test for API: TSHttpTxnTransformRespGet
7596 //                    TSHttpTxnTransformedRespCache
7597 //                    TSHttpTxnUntransformedRespCache
7598 ///////////////////////////////////////////////////////
7599 
7600 /** Append Transform Data Structure Ends **/
7601 
7602 struct TransformTestData {
7603   RegressionTest *test;
7604   int *pstatus;
7605   SocketServer *os;
7606   ClientTxn *browser1;
7607   ClientTxn *browser2;
7608   ClientTxn *browser3;
7609   ClientTxn *browser4;
7610   char *request1;
7611   char *request2;
7612   bool test_passed_txn_transform_resp_get;
7613   bool test_passed_txn_transformed_resp_cache;
7614   bool test_passed_txn_untransformed_resp_cache;
7615   bool test_passed_transform_create;
7616   int req_no;
7617   uint32_t magic;
7618 };
7619 
7620 /** Append Transform Data Structure **/
7621 struct AppendTransformTestData {
7622   TSVIO output_vio               = nullptr;
7623   TSIOBuffer output_buffer       = nullptr;
7624   TSIOBufferReader output_reader = nullptr;
7625   TransformTestData *test_data   = nullptr;
7626   int append_needed              = 1;
7627 
~AppendTransformTestDataAppendTransformTestData7628   ~AppendTransformTestData()
7629   {
7630     if (output_buffer) {
7631       TSIOBufferDestroy(output_buffer);
7632     }
7633   }
7634 };
7635 
7636 /**** Append Transform Code (Tailored to needs)****/
7637 
7638 static TSIOBuffer append_buffer;
7639 static TSIOBufferReader append_buffer_reader;
7640 static int64_t append_buffer_length;
7641 
7642 static void
handle_transform(TSCont contp)7643 handle_transform(TSCont contp)
7644 {
7645   TSVConn output_conn;
7646   TSVIO write_vio;
7647   int64_t towrite;
7648   int64_t avail;
7649 
7650   /* Get the output connection where we'll write data to. */
7651   output_conn = TSTransformOutputVConnGet(contp);
7652 
7653   /* Get the write VIO for the write operation that was performed on
7654      ourself. This VIO contains the buffer that we are to read from
7655      as well as the continuation we are to call when the buffer is
7656      empty. */
7657   write_vio = TSVConnWriteVIOGet(contp);
7658 
7659   /* Get our data structure for this operation. The private data
7660      structure contains the output VIO and output buffer.
7661   */
7662   auto *data = static_cast<AppendTransformTestData *>(TSContDataGet(contp));
7663   if (!data->output_buffer) {
7664     towrite = TSVIONBytesGet(write_vio);
7665     if (towrite != INT64_MAX) {
7666       towrite += append_buffer_length;
7667     }
7668     data->output_buffer = TSIOBufferCreate();
7669     data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
7670     data->output_vio    = TSVConnWrite(output_conn, contp, data->output_reader, towrite);
7671   }
7672   ink_assert(data->output_vio);
7673 
7674   /* We also check to see if the write VIO's buffer is non-NULL. A
7675      NULL buffer indicates that the write operation has been
7676      shutdown and that the continuation does not want us to send any
7677      more WRITE_READY or WRITE_COMPLETE events. For this simplistic
7678      transformation that means we're done. In a more complex
7679      transformation we might have to finish writing the transformed
7680      data to our output connection. */
7681   if (!TSVIOBufferGet(write_vio)) {
7682     if (data->append_needed) {
7683       data->append_needed = 0;
7684       TSIOBufferCopy(TSVIOBufferGet(data->output_vio), append_buffer_reader, append_buffer_length, 0);
7685     }
7686 
7687     TSVIONBytesSet(data->output_vio, TSVIONDoneGet(write_vio) + append_buffer_length);
7688     TSVIOReenable(data->output_vio);
7689     return;
7690   }
7691 
7692   /* Determine how much data we have left to read. For this append
7693      transform plugin this is also the amount of data we have left
7694      to write to the output connection. */
7695   towrite = TSVIONTodoGet(write_vio);
7696   if (towrite > 0) {
7697     /* The amount of data left to read needs to be truncated by
7698        the amount of data actually in the read buffer. */
7699     avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
7700     if (towrite > avail) {
7701       towrite = avail;
7702     }
7703 
7704     if (towrite > 0) {
7705       /* Copy the data from the read buffer to the output buffer. */
7706       TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(write_vio), towrite, 0);
7707 
7708       /* Tell the read buffer that we have read the data and are no
7709          longer interested in it. */
7710       TSIOBufferReaderConsume(TSVIOReaderGet(write_vio), towrite);
7711 
7712       /* Modify the write VIO to reflect how much data we've
7713          completed. */
7714       TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
7715     }
7716   }
7717 
7718   /* Now we check the write VIO to see if there is data left to
7719      read. */
7720   if (TSVIONTodoGet(write_vio) > 0) {
7721     if (towrite > 0) {
7722       /* If there is data left to read, then we reenable the output
7723          connection by reenabling the output VIO. This will wakeup
7724          the output connection and allow it to consume data from the
7725          output buffer. */
7726       TSVIOReenable(data->output_vio);
7727 
7728       /* Call back the write VIO continuation to let it know that we
7729          are ready for more data. */
7730       TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
7731     }
7732   } else {
7733     if (data->append_needed) {
7734       data->append_needed = 0;
7735       TSIOBufferCopy(TSVIOBufferGet(data->output_vio), append_buffer_reader, append_buffer_length, 0);
7736     }
7737 
7738     /* If there is no data left to read, then we modify the output
7739        VIO to reflect how much data the output connection should
7740        expect. This allows the output connection to know when it
7741        is done reading. We then reenable the output connection so
7742        that it can consume the data we just gave it. */
7743     TSVIONBytesSet(data->output_vio, TSVIONDoneGet(write_vio) + append_buffer_length);
7744     TSVIOReenable(data->output_vio);
7745 
7746     /* Call back the write VIO continuation to let it know that we
7747        have completed the write operation. */
7748     TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
7749   }
7750 }
7751 
7752 static int
transformtest_transform(TSCont contp,TSEvent event,void *)7753 transformtest_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
7754 {
7755   auto *data = static_cast<AppendTransformTestData *>(TSContDataGet(contp));
7756   if (data->test_data->test_passed_transform_create == false) {
7757     data->test_data->test_passed_transform_create = true;
7758     SDK_RPRINT(data->test_data->test, "TSTransformCreate", "TestCase1", TC_PASS, "ok");
7759   }
7760   /* Check to see if the transformation has been closed by a call to
7761      TSVConnClose. */
7762   if (TSVConnClosedGet(contp)) {
7763     delete data;
7764     TSContDestroy(contp);
7765     return 0;
7766   } else {
7767     switch (event) {
7768     case TS_EVENT_ERROR: {
7769       TSVIO write_vio;
7770 
7771       /* Get the write VIO for the write operation that was
7772          performed on ourself. This VIO contains the continuation of
7773          our parent transformation. */
7774       write_vio = TSVConnWriteVIOGet(contp);
7775 
7776       /* Call back the write VIO continuation to let it know that we
7777          have completed the write operation. */
7778       TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio);
7779     } break;
7780     case TS_EVENT_VCONN_WRITE_COMPLETE:
7781       /* When our output connection says that it has finished
7782          reading all the data we've written to it then we should
7783          shutdown the write portion of its connection to
7784          indicate that we don't want to hear about it anymore. */
7785       TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
7786       break;
7787     case TS_EVENT_VCONN_WRITE_READY:
7788     default:
7789       /* If we get a WRITE_READY event or any other type of
7790          event (sent, perhaps, because we were reenabled) then
7791          we'll attempt to transform more data. */
7792       handle_transform(contp);
7793       break;
7794     }
7795   }
7796 
7797   return 0;
7798 }
7799 
7800 static int
transformable(TSHttpTxn txnp,TransformTestData * data)7801 transformable(TSHttpTxn txnp, TransformTestData *data)
7802 {
7803   TSMBuffer bufp;
7804   TSMLoc hdr_loc;
7805   int ret = 0;
7806 
7807   if (TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
7808     SDK_RPRINT(data->test, "TSHttpTxnTransform", "", TC_FAIL, "[transformable]: TSHttpTxnServerRespGet return 0");
7809     return ret;
7810   }
7811 
7812   /*
7813    *  We are only interested in "200 OK" responses.
7814    */
7815 
7816   if (TS_HTTP_STATUS_OK == TSHttpHdrStatusGet(bufp, hdr_loc)) {
7817     ret = 1;
7818   }
7819 
7820   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
7821   return ret; /* not a 200 */
7822 }
7823 
7824 static void
transform_add(TSHttpTxn txnp,TransformTestData * test_data)7825 transform_add(TSHttpTxn txnp, TransformTestData *test_data)
7826 {
7827   TSVConn connp = TSTransformCreate(transformtest_transform, txnp);
7828   if (connp == nullptr) {
7829     SDK_RPRINT(test_data->test, "TSHttpTxnTransform", "", TC_FAIL, "Unable to create Transformation.");
7830     return;
7831   }
7832 
7833   // Add data to the continuation
7834   auto *data      = new AppendTransformTestData;
7835   data->test_data = test_data;
7836   TSContDataSet(connp, data);
7837 
7838   TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
7839   return;
7840 }
7841 
7842 static int
load(const char * append_string)7843 load(const char *append_string)
7844 {
7845   TSIOBufferBlock blk;
7846   char *p;
7847   int64_t avail;
7848 
7849   append_buffer        = TSIOBufferCreate();
7850   append_buffer_reader = TSIOBufferReaderAlloc(append_buffer);
7851 
7852   blk = TSIOBufferStart(append_buffer);
7853   p   = TSIOBufferBlockWriteStart(blk, &avail);
7854 
7855   ink_strlcpy(p, append_string, avail);
7856   if (append_string != nullptr) {
7857     TSIOBufferProduce(append_buffer, strlen(append_string));
7858   }
7859 
7860   append_buffer_length = TSIOBufferReaderAvail(append_buffer_reader);
7861 
7862   return 1;
7863 }
7864 
7865 /**** Append Transform Code Ends ****/
7866 
7867 static int
transform_hook_handler(TSCont contp,TSEvent event,void * edata)7868 transform_hook_handler(TSCont contp, TSEvent event, void *edata)
7869 {
7870   TSHttpTxn txnp          = nullptr;
7871   TransformTestData *data = nullptr;
7872 
7873   CHECK_SPURIOUS_EVENT(contp, event, edata);
7874   data = static_cast<TransformTestData *>(TSContDataGet(contp));
7875 
7876   switch (event) {
7877   case TS_EVENT_HTTP_READ_REQUEST_HDR:
7878     txnp = static_cast<TSHttpTxn>(edata);
7879     TSSkipRemappingSet(txnp, 1);
7880     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7881     break;
7882   case TS_EVENT_HTTP_READ_RESPONSE_HDR:
7883     txnp = static_cast<TSHttpTxn>(edata);
7884     /* Setup hooks for Transformation */
7885     if (transformable(txnp, data)) {
7886       transform_add(txnp, data);
7887     }
7888     /* Call TransformedRespCache or UntransformedRespCache depending on request */
7889     {
7890       TSMBuffer bufp;
7891       TSMLoc hdr;
7892       TSMLoc field;
7893 
7894       if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr) != TS_SUCCESS) {
7895         SDK_RPRINT(data->test, "TSHttpTxnTransform", "TestCase", TC_FAIL, "TSHttpTxnClientReqGet returns 0");
7896       } else {
7897         if (TS_NULL_MLOC == (field = TSMimeHdrFieldFind(bufp, hdr, "Request", -1))) {
7898           SDK_RPRINT(data->test, "TSHttpTxnTransform", "TestCase", TC_FAIL, "Didn't find field request");
7899         } else {
7900           int reqid = TSMimeHdrFieldValueIntGet(bufp, hdr, field, 0);
7901           if (reqid == 1) {
7902             TSHttpTxnTransformedRespCache(txnp, 0);
7903             TSHttpTxnUntransformedRespCache(txnp, 1);
7904           }
7905           if (reqid == 2) {
7906             TSHttpTxnTransformedRespCache(txnp, 1);
7907             TSHttpTxnUntransformedRespCache(txnp, 0);
7908           }
7909           if (TSHandleMLocRelease(bufp, hdr, field) != TS_SUCCESS) {
7910             SDK_RPRINT(data->test, "TSHttpTxnTransform", "TestCase", TC_FAIL,
7911                        "Unable to release handle to field in Client request");
7912           }
7913         }
7914         if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr) != TS_SUCCESS) {
7915           SDK_RPRINT(data->test, "TSHttpTxnTransform", "TestCase", TC_FAIL, "Unable to release handle to Client request");
7916         }
7917       }
7918     }
7919 
7920     /* Add the transaction hook to SEND_RESPONSE_HDR_HOOK */
7921     TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
7922     /* Reenable the transaction */
7923     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7924     break;
7925 
7926   case TS_EVENT_HTTP_SEND_RESPONSE_HDR: {
7927     TSMBuffer bufp;
7928     TSMLoc hdr;
7929     txnp = static_cast<TSHttpTxn>(edata);
7930     if (TSHttpTxnTransformRespGet(txnp, &bufp, &hdr) != TS_SUCCESS) {
7931       SDK_RPRINT(data->test, "TSHttpTxnTransformRespGet", "TestCase", TC_FAIL, "TSHttpTxnTransformRespGet returns 0");
7932       data->test_passed_txn_transform_resp_get = false;
7933     } else {
7934       if ((bufp == reinterpret_cast<TSMBuffer>(&(((HttpSM *)txnp)->t_state.hdr_info.transform_response))) &&
7935           (hdr == reinterpret_cast<TSMLoc>((&(((HttpSM *)txnp)->t_state.hdr_info.transform_response))->m_http))) {
7936         SDK_RPRINT(data->test, "TSHttpTxnTransformRespGet", "TestCase", TC_PASS, "ok");
7937       } else {
7938         SDK_RPRINT(data->test, "TSHttpTxnTransformRespGet", "TestCase", TC_FAIL, "Value's Mismatch");
7939         data->test_passed_txn_transform_resp_get = false;
7940       }
7941       if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr) != TS_SUCCESS) {
7942         SDK_RPRINT(data->test, "TSHttpTxnTransformRespGet", "TestCase", TC_FAIL,
7943                    "Unable to release handle to Transform header handle");
7944       }
7945     }
7946   }
7947     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
7948     break;
7949 
7950   case TS_EVENT_IMMEDIATE:
7951   case TS_EVENT_TIMEOUT:
7952 
7953     switch (data->req_no) {
7954     case 1:
7955       if (data->browser1->status == REQUEST_INPROGRESS) {
7956         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7957         return 0;
7958       }
7959       data->req_no++;
7960       Debug(UTDBG_TAG "_transform", "Running Browser 2");
7961       synclient_txn_send_request(data->browser2, data->request2);
7962       TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7963       return 0;
7964     case 2:
7965       if (data->browser2->status == REQUEST_INPROGRESS) {
7966         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7967         return 0;
7968       }
7969       data->req_no++;
7970       Debug(UTDBG_TAG "_transform", "Running Browser 3");
7971       synclient_txn_send_request(data->browser3, data->request1);
7972       TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7973       return 0;
7974     case 3:
7975       if (data->browser3->status == REQUEST_INPROGRESS) {
7976         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7977         return 0;
7978       }
7979       data->req_no++;
7980       Debug(UTDBG_TAG "_transform", "Running Browser 4");
7981       synclient_txn_send_request(data->browser4, data->request2);
7982       TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7983       return 0;
7984     case 4:
7985       if (data->browser4->status == REQUEST_INPROGRESS) {
7986         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
7987         return 0;
7988       }
7989       synserver_delete(data->os);
7990       data->os = nullptr;
7991       data->req_no++;
7992       TSfree(data->request1);
7993       TSfree(data->request2);
7994       // for squid log: if this is the last (or only) test in your
7995       // regression run you will not see any log entries in squid
7996       // (because logging is buffered and not flushed before
7997       // termination when running regressions)
7998       // sleep(10);
7999       break;
8000     default:
8001       SDK_RPRINT(data->test, "TSHttpTxnTransform", "TestCase", TC_FAIL, "Something terribly wrong with the test");
8002       exit(0);
8003     }
8004     /* Browser got the response. test is over */
8005     {
8006       /* Check if we got the response we were expecting or not */
8007       if ((strstr(data->browser1->response, TRANSFORM_APPEND_STRING) != nullptr) &&
8008           (strstr(data->browser3->response, TRANSFORM_APPEND_STRING) == nullptr)) {
8009         SDK_RPRINT(data->test, "TSHttpTxnUntransformedResponseCache", "TestCase1", TC_PASS, "ok");
8010         data->test_passed_txn_untransformed_resp_cache = true;
8011       } else {
8012         SDK_RPRINT(data->test, "TSHttpTxnUntransformedResponseCache", "TestCase1", TC_FAIL, "Value's Mismatch");
8013       }
8014 
8015       if ((strstr(data->browser2->response, TRANSFORM_APPEND_STRING) != nullptr) &&
8016           (strstr(data->browser4->response, TRANSFORM_APPEND_STRING) != nullptr)) {
8017         SDK_RPRINT(data->test, "TSHttpTxnTransformedResponseCache", "TestCase1", TC_PASS, "ok");
8018         data->test_passed_txn_transformed_resp_cache = true;
8019       } else {
8020         SDK_RPRINT(data->test, "TSHttpTxnTransformedResponseCache", "TestCase1", TC_FAIL, "Value's Mismatch");
8021       }
8022 
8023       /* Note: response is available using test->browser->response pointer */
8024       *(data->pstatus) = REGRESSION_TEST_PASSED;
8025       if (data->browser1->status != REQUEST_SUCCESS) {
8026         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "Browser 1 status was not REQUEST_SUCCESS");
8027         *(data->pstatus) = REGRESSION_TEST_FAILED;
8028       }
8029       if (data->browser2->status != REQUEST_SUCCESS) {
8030         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "Browser 2 status was not REQUEST_SUCCESS");
8031         *(data->pstatus) = REGRESSION_TEST_FAILED;
8032       }
8033       if (data->browser3->status != REQUEST_SUCCESS) {
8034         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "Browser 3 status was not REQUEST_SUCCESS");
8035         *(data->pstatus) = REGRESSION_TEST_FAILED;
8036       }
8037       if (data->browser4->status != REQUEST_SUCCESS) {
8038         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "Browser 4 status was not REQUEST_SUCCESS");
8039         *(data->pstatus) = REGRESSION_TEST_FAILED;
8040       }
8041       if (data->test_passed_txn_transform_resp_get != true) {
8042         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "did not pass transform_resp_get");
8043         *(data->pstatus) = REGRESSION_TEST_FAILED;
8044       }
8045       if (data->test_passed_txn_transformed_resp_cache != true) {
8046         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "did not pass transformed_resp_cache");
8047         *(data->pstatus) = REGRESSION_TEST_FAILED;
8048       }
8049       if (data->test_passed_txn_untransformed_resp_cache != true) {
8050         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "did not pass untransformed_resp_cache");
8051         *(data->pstatus) = REGRESSION_TEST_FAILED;
8052       }
8053       if (data->test_passed_transform_create != true) {
8054         SDK_RPRINT(data->test, "TSTransformCreate", "TestCase1", TC_FAIL, "did not pass transform_create");
8055         *(data->pstatus) = REGRESSION_TEST_FAILED;
8056       }
8057       // transaction is over. clean up.
8058       synclient_txn_delete(data->browser1);
8059       synclient_txn_delete(data->browser2);
8060       synclient_txn_delete(data->browser3);
8061       synclient_txn_delete(data->browser4);
8062 
8063       TSContDataSet(contp, nullptr);
8064       data->magic = MAGIC_DEAD;
8065       TSfree(data);
8066     }
8067     break;
8068 
8069   default:
8070     *(data->pstatus) = REGRESSION_TEST_FAILED;
8071     SDK_RPRINT(data->test, "TSHttpTxnTransform", "TestCase1", TC_FAIL, "Unexpected event %d", event);
8072     break;
8073   }
8074   return 0;
8075 }
8076 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpTxnTransform)8077 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpTxnTransform)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8078 {
8079   *pstatus = REGRESSION_TEST_INPROGRESS;
8080 
8081   Debug(UTDBG_TAG "_transform", "Starting test");
8082 
8083   TSCont cont = TSContCreate(transform_hook_handler, TSMutexCreate());
8084   if (cont == nullptr) {
8085     SDK_RPRINT(test, "TSHttpSsn", "TestCase1", TC_FAIL, "Unable to create Continuation.");
8086     *pstatus = REGRESSION_TEST_FAILED;
8087     return;
8088   }
8089 
8090   TransformTestData *socktest                      = static_cast<TransformTestData *>(TSmalloc(sizeof(TransformTestData)));
8091   socktest->test                                   = test;
8092   socktest->pstatus                                = pstatus;
8093   socktest->test_passed_txn_transform_resp_get     = true;
8094   socktest->test_passed_txn_transformed_resp_cache = false;
8095   socktest->test_passed_txn_transformed_resp_cache = false;
8096   socktest->test_passed_transform_create           = false;
8097   socktest->req_no                                 = 1;
8098   socktest->magic                                  = MAGIC_ALIVE;
8099   TSContDataSet(cont, socktest);
8100 
8101   /* Prepare the buffer to be appended to responses */
8102   load(TRANSFORM_APPEND_STRING);
8103 
8104   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont); // so we can skip remapping
8105 
8106   /* Register to HTTP hooks that are called in case of a cache MISS */
8107   TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, cont);
8108 
8109   /* Create a new synthetic server */
8110   socktest->os = synserver_create(SYNSERVER_LISTEN_PORT);
8111   synserver_start(socktest->os);
8112 
8113   /* Create a client transaction */
8114   socktest->browser1 = synclient_txn_create();
8115   socktest->browser2 = synclient_txn_create();
8116   socktest->browser3 = synclient_txn_create();
8117   socktest->browser4 = synclient_txn_create();
8118   socktest->request1 = generate_request(4);
8119   socktest->request2 = generate_request(5);
8120   Debug(UTDBG_TAG "_transform", "Running Browser 1");
8121   synclient_txn_send_request(socktest->browser1, socktest->request1);
8122   // synclient_txn_send_request(socktest->browser2, socktest->request2);
8123 
8124   /* Wait until transaction is done */
8125   TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
8126 
8127   return;
8128 }
8129 
8130 //////////////////////////////////////////////
8131 //       SDK_API_TSHttpTxnAltInfo
8132 //
8133 // Unit Test for API: TSHttpTxnCachedReqGet
8134 //                    TSHttpTxnCachedRespGet
8135 //////////////////////////////////////////////
8136 
8137 struct AltInfoTestData {
8138   RegressionTest *test;
8139   int *pstatus;
8140   SocketServer *os;
8141   ClientTxn *browser1;
8142   ClientTxn *browser2;
8143   ClientTxn *browser3;
8144   char *request1;
8145   char *request2;
8146   char *request3;
8147   bool test_passed_txn_alt_info_client_req_get;
8148   bool test_passed_txn_alt_info_cached_req_get;
8149   bool test_passed_txn_alt_info_cached_resp_get;
8150   bool test_passed_txn_alt_info_quality_set;
8151   bool run_at_least_once;
8152   bool first_time;
8153   int magic;
8154 };
8155 
8156 static int
altinfo_hook_handler(TSCont contp,TSEvent event,void * edata)8157 altinfo_hook_handler(TSCont contp, TSEvent event, void *edata)
8158 {
8159   AltInfoTestData *data = nullptr;
8160   TSHttpTxn txnp        = nullptr;
8161 
8162   CHECK_SPURIOUS_EVENT(contp, event, edata);
8163   data = static_cast<AltInfoTestData *>(TSContDataGet(contp));
8164 
8165   switch (event) {
8166   case TS_EVENT_HTTP_READ_REQUEST_HDR:
8167     txnp = static_cast<TSHttpTxn>(edata);
8168     TSSkipRemappingSet(txnp, 1);
8169     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
8170     break;
8171 
8172   case TS_EVENT_HTTP_SELECT_ALT: {
8173     TSMBuffer clientreqbuf;
8174     TSMBuffer cachereqbuf;
8175     TSMBuffer cacherespbuf;
8176 
8177     TSMLoc clientreqhdr;
8178     TSMLoc cachereqhdr;
8179     TSMLoc cacheresphdr;
8180 
8181     TSHttpAltInfo infop = static_cast<TSHttpAltInfo>(edata);
8182 
8183     data->run_at_least_once = true;
8184     if (TSHttpAltInfoClientReqGet(infop, &clientreqbuf, &clientreqhdr) != TS_SUCCESS) {
8185       SDK_RPRINT(data->test, "TSHttpAltInfoClientReqGet", "TestCase", TC_FAIL,
8186                  "TSHttpAltInfoClientReqGet doesn't return TS_SUCCESS");
8187       data->test_passed_txn_alt_info_client_req_get = false;
8188     } else {
8189       if ((clientreqbuf == reinterpret_cast<TSMBuffer>(&(((HttpAltInfo *)infop)->m_client_req))) &&
8190           (clientreqhdr == reinterpret_cast<TSMLoc>(((HttpAltInfo *)infop)->m_client_req.m_http))) {
8191         SDK_RPRINT(data->test, "TSHttpAltInfoClientReqGet", "TestCase", TC_PASS, "ok");
8192       } else {
8193         SDK_RPRINT(data->test, "TSHttpAltInfoClientReqGet", "TestCase", TC_FAIL, "Value's Mismatch");
8194         data->test_passed_txn_alt_info_client_req_get = false;
8195       }
8196     }
8197 
8198     if (TSHttpAltInfoCachedReqGet(infop, &cachereqbuf, &cachereqhdr) != TS_SUCCESS) {
8199       SDK_RPRINT(data->test, "TSHttpAltInfoCachedReqGet", "TestCase", TC_FAIL,
8200                  "TSHttpAltInfoCachedReqGet doesn't return TS_SUCCESS");
8201       data->test_passed_txn_alt_info_cached_req_get = false;
8202     } else {
8203       if ((cachereqbuf == reinterpret_cast<TSMBuffer>(&(((HttpAltInfo *)infop)->m_cached_req))) &&
8204           (cachereqhdr == reinterpret_cast<TSMLoc>(((HttpAltInfo *)infop)->m_cached_req.m_http))) {
8205         SDK_RPRINT(data->test, "TSHttpAltInfoCachedReqGet", "TestCase", TC_PASS, "ok");
8206       } else {
8207         SDK_RPRINT(data->test, "TSHttpAltInfoCachedReqGet", "TestCase", TC_FAIL, "Value's Mismatch");
8208         data->test_passed_txn_alt_info_cached_req_get = false;
8209       }
8210     }
8211 
8212     if (TSHttpAltInfoCachedRespGet(infop, &cacherespbuf, &cacheresphdr) != TS_SUCCESS) {
8213       SDK_RPRINT(data->test, "TSHttpAltInfoCachedRespGet", "TestCase", TC_FAIL,
8214                  "TSHttpAltInfoCachedRespGet doesn't return TS_SUCCESS");
8215       data->test_passed_txn_alt_info_cached_resp_get = false;
8216     } else {
8217       if ((cacherespbuf == reinterpret_cast<TSMBuffer>(&(((HttpAltInfo *)infop)->m_cached_resp))) &&
8218           (cacheresphdr == reinterpret_cast<TSMLoc>(((HttpAltInfo *)infop)->m_cached_resp.m_http))) {
8219         SDK_RPRINT(data->test, "TSHttpAltInfoCachedRespGet", "TestCase", TC_PASS, "ok");
8220       } else {
8221         SDK_RPRINT(data->test, "TSHttpAltInfoCachedRespGet", "TestCase", TC_FAIL, "Value's Mismatch");
8222         data->test_passed_txn_alt_info_cached_resp_get = false;
8223       }
8224     }
8225 
8226     TSHttpAltInfoQualitySet(infop, 0.5);
8227     SDK_RPRINT(data->test, "TSHttpAltInfoQualitySet", "TestCase", TC_PASS, "ok");
8228   }
8229 
8230   break;
8231 
8232   case TS_EVENT_IMMEDIATE:
8233   case TS_EVENT_TIMEOUT:
8234     /* Browser still waiting the response ? */
8235     if (data->first_time == true) {
8236       if ((data->browser1->status == REQUEST_INPROGRESS) || (data->browser2->status == REQUEST_INPROGRESS)) {
8237         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
8238         return 0;
8239       }
8240     } else {
8241       if (data->browser3->status == REQUEST_INPROGRESS) {
8242         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
8243         return 0;
8244       }
8245     }
8246 
8247     /* Browser got the response. test is over. clean up */
8248     {
8249       /* If this is the first time, then both the responses are in cache and we should make */
8250       /* another request to get cache hit */
8251       if (data->first_time == true) {
8252         data->first_time = false;
8253         /* Kill the origin server */
8254         synserver_delete(data->os);
8255         data->os = nullptr;
8256         // ink_release_assert(0);
8257         /* Send another similar client request */
8258         synclient_txn_send_request(data->browser3, data->request3);
8259 
8260         /* Register to HTTP hooks that are called in case of alternate selection */
8261         TSHttpHookAdd(TS_HTTP_SELECT_ALT_HOOK, contp);
8262         TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
8263         return 0;
8264       }
8265 
8266       /* Note: response is available using test->browser->response pointer */
8267       if ((data->browser3->status == REQUEST_SUCCESS) && (data->test_passed_txn_alt_info_client_req_get == true) &&
8268           (data->test_passed_txn_alt_info_cached_req_get == true) && (data->test_passed_txn_alt_info_cached_resp_get == true) &&
8269           (data->test_passed_txn_alt_info_quality_set == true) && (data->run_at_least_once == true)) {
8270         *(data->pstatus) = REGRESSION_TEST_PASSED;
8271       } else {
8272         if (data->run_at_least_once == false) {
8273           SDK_RPRINT(data->test, "TSHttpAltInfo", "All", TC_FAIL, "Test not executed even once");
8274         }
8275         *(data->pstatus) = REGRESSION_TEST_FAILED;
8276       }
8277 
8278       // transaction is over. clean up.
8279       synclient_txn_delete(data->browser1);
8280       synclient_txn_delete(data->browser2);
8281       synclient_txn_delete(data->browser3);
8282 
8283       TSfree(data->request1);
8284       TSfree(data->request2);
8285       TSfree(data->request3);
8286 
8287       data->magic = MAGIC_DEAD;
8288       TSfree(data);
8289       TSContDataSet(contp, nullptr);
8290     }
8291     break;
8292 
8293   default:
8294     *(data->pstatus) = REGRESSION_TEST_FAILED;
8295     SDK_RPRINT(data->test, "TSHttpTxnCache", "TestCase1", TC_FAIL, "Unexpected event %d", event);
8296     break;
8297   }
8298   return 0;
8299 }
8300 
EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpAltInfo)8301 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpAltInfo)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8302 {
8303   *pstatus = REGRESSION_TEST_INPROGRESS;
8304 
8305   TSCont cont = TSContCreate(altinfo_hook_handler, TSMutexCreate());
8306   if (cont == nullptr) {
8307     SDK_RPRINT(test, "TSHttpSsn", "TestCase1", TC_FAIL, "Unable to create Continuation.");
8308     *pstatus = REGRESSION_TEST_FAILED;
8309     return;
8310   }
8311 
8312   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont); // so we can skip remapping
8313 
8314   AltInfoTestData *socktest                          = static_cast<AltInfoTestData *>(TSmalloc(sizeof(AltInfoTestData)));
8315   socktest->test                                     = test;
8316   socktest->pstatus                                  = pstatus;
8317   socktest->test_passed_txn_alt_info_client_req_get  = true;
8318   socktest->test_passed_txn_alt_info_cached_req_get  = true;
8319   socktest->test_passed_txn_alt_info_cached_resp_get = true;
8320   socktest->test_passed_txn_alt_info_quality_set     = true;
8321   socktest->run_at_least_once                        = false;
8322   socktest->first_time                               = true;
8323   socktest->magic                                    = MAGIC_ALIVE;
8324   TSContDataSet(cont, socktest);
8325 
8326   /* Create a new synthetic server */
8327   socktest->os = synserver_create(SYNSERVER_LISTEN_PORT);
8328   synserver_start(socktest->os);
8329 
8330   /* Create a client transaction */
8331   socktest->browser1 = synclient_txn_create();
8332   socktest->browser2 = synclient_txn_create();
8333   socktest->browser3 = synclient_txn_create();
8334   socktest->request1 = generate_request(6);
8335   socktest->request2 = generate_request(7);
8336   socktest->request3 = generate_request(8);
8337   synclient_txn_send_request(socktest->browser1, socktest->request1);
8338   synclient_txn_send_request(socktest->browser2, socktest->request2);
8339 
8340   /* Wait until transaction is done */
8341   TSContScheduleOnPool(cont, 25, TS_THREAD_POOL_NET);
8342 
8343   return;
8344 }
8345 
8346 //////////////////////////////////////////////
8347 //       SDK_API_TSHttpConnect
8348 //
8349 // Unit Test for APIs:
8350 //      - TSHttpConnect
8351 //      - TSHttpTxnIntercept
8352 //      - TSHttpTxnInterceptServer
8353 //
8354 //
8355 // 2 Test cases.
8356 //
8357 // Same test strategy:
8358 //  - create a synthetic server listening on port A
8359 //  - use HttpConnect to send a request to TS for an url on a remote host H, port B
8360 //  - use TxnIntercept or TxnServerIntercept to forward the request
8361 //    to the synthetic server on local host, port A
8362 //  - make sure response is correct
8363 //
8364 //////////////////////////////////////////////
8365 
8366 // Important: we create servers listening on different port than the default one
8367 // to make sure our synthetic servers are called
8368 
8369 #define TEST_CASE_CONNECT_ID1 9  // TSHttpTxnIntercept
8370 #define TEST_CASE_CONNECT_ID2 10 // TSHttpTxnServerIntercept
8371 
8372 struct ConnectTestData {
8373   RegressionTest *test;
8374   int *pstatus;
8375   int test_case;
8376   TSVConn vc;
8377   SocketServer *os;
8378   ClientTxn *browser;
8379   char *request;
8380   unsigned long magic;
8381 };
8382 
8383 static int
cont_test_handler(TSCont contp,TSEvent event,void * edata)8384 cont_test_handler(TSCont contp, TSEvent event, void *edata)
8385 {
8386   TSHttpTxn txnp        = static_cast<TSHttpTxn>(edata);
8387   ConnectTestData *data = nullptr;
8388   int request_id        = -1;
8389 
8390   CHECK_SPURIOUS_EVENT(contp, event, edata);
8391   data = static_cast<ConnectTestData *>(TSContDataGet(contp));
8392 
8393   TSReleaseAssert(data->magic == MAGIC_ALIVE);
8394   TSReleaseAssert((data->test_case == TEST_CASE_CONNECT_ID1) || (data->test_case == TEST_CASE_CONNECT_ID2));
8395 
8396   TSDebug(UTDBG_TAG, "Calling cont_test_handler with event %s (%d)", TSHttpEventNameLookup(event), event);
8397 
8398   switch (event) {
8399   case TS_EVENT_HTTP_READ_REQUEST_HDR:
8400     TSDebug(UTDBG_TAG, "cont_test_handler: event READ_REQUEST");
8401 
8402     // First make sure we're getting called for either request 9 or txn 10
8403     // Otherwise, this is a request sent by another test. do nothing.
8404     request_id = get_request_id(txnp);
8405     TSReleaseAssert(request_id != -1);
8406 
8407     TSDebug(UTDBG_TAG, "cont_test_handler: Request id = %d", request_id);
8408 
8409     if ((request_id != TEST_CASE_CONNECT_ID1) && (request_id != TEST_CASE_CONNECT_ID2)) {
8410       TSDebug(UTDBG_TAG, "This is not an event for this test !");
8411       TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
8412       goto done;
8413     }
8414 
8415     if ((request_id == TEST_CASE_CONNECT_ID1) && (data->test_case == TEST_CASE_CONNECT_ID1)) {
8416       TSDebug(UTDBG_TAG, "Calling TSHttpTxnIntercept");
8417       TSHttpTxnIntercept(data->os->accept_cont, txnp);
8418     } else if ((request_id == TEST_CASE_CONNECT_ID2) && (data->test_case == TEST_CASE_CONNECT_ID2)) {
8419       TSDebug(UTDBG_TAG, "Calling TSHttpTxnServerIntercept");
8420       TSHttpTxnServerIntercept(data->os->accept_cont, txnp);
8421     }
8422 
8423     TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
8424     break;
8425 
8426   case TS_EVENT_TIMEOUT:
8427     /* Browser still waiting the response ? */
8428     if (data->browser->status == REQUEST_INPROGRESS) {
8429       TSDebug(UTDBG_TAG, "Browser still waiting response...");
8430       TSContScheduleOnPool(contp, 25, TS_THREAD_POOL_NET);
8431     }
8432     /* Browser got the response */
8433     else {
8434       /* Check if browser response body is the one we expected */
8435       char *body_response = get_body_ptr(data->browser->response);
8436       const char *body_expected;
8437       if (data->test_case == TEST_CASE_CONNECT_ID1) {
8438         body_expected = "Body for response 9";
8439       } else {
8440         body_expected = "Body for response 10";
8441       }
8442       TSDebug(UTDBG_TAG, "Body Response = \n|%s|\nBody Expected = \n|%s|", body_response ? body_response : "*NULL*", body_expected);
8443 
8444       if (!body_response || strncmp(body_response, body_expected, strlen(body_expected)) != 0) {
8445         if (data->test_case == TEST_CASE_CONNECT_ID1) {
8446           SDK_RPRINT(data->test, "TSHttpConnect", "TestCase1", TC_FAIL, "Unexpected response");
8447           SDK_RPRINT(data->test, "TSHttpTxnIntercept", "TestCase1", TC_FAIL, "Unexpected response");
8448         } else {
8449           SDK_RPRINT(data->test, "TSHttpConnect", "TestCase2", TC_FAIL, "Unexpected response");
8450           SDK_RPRINT(data->test, "TSHttpTxnServerIntercept", "TestCase2", TC_FAIL, "Unexpected response");
8451         }
8452         *(data->pstatus) = REGRESSION_TEST_FAILED;
8453 
8454       } else {
8455         if (data->test_case == TEST_CASE_CONNECT_ID1) {
8456           SDK_RPRINT(data->test, "TSHttpConnect", "TestCase1", TC_PASS, "ok");
8457           SDK_RPRINT(data->test, "TSHttpTxnIntercept", "TestCase1", TC_PASS, "ok");
8458         } else {
8459           SDK_RPRINT(data->test, "TSHttpConnect", "TestCase2", TC_PASS, "ok");
8460           SDK_RPRINT(data->test, "TSHttpTxnServerIntercept", "TestCase2", TC_PASS, "ok");
8461         }
8462         *(data->pstatus) = REGRESSION_TEST_PASSED;
8463       }
8464 
8465       // transaction is over. clean it up.
8466       synclient_txn_delete(data->browser);
8467       synserver_delete(data->os);
8468       data->os    = nullptr;
8469       data->magic = MAGIC_DEAD;
8470       TSfree(data);
8471       TSContDataSet(contp, nullptr);
8472     }
8473     break;
8474 
8475   default:
8476     *(data->pstatus) = REGRESSION_TEST_FAILED;
8477     SDK_RPRINT(data->test, "TSHttpConnect", "TestCase1 or 2", TC_FAIL, "Unexpected event %d", event);
8478     break;
8479   }
8480 
8481 done:
8482   return TS_EVENT_IMMEDIATE;
8483 }
8484 
EXCLUSIVE_REGRESSION_TEST(SDK_API_TSHttpConnectIntercept)8485 EXCLUSIVE_REGRESSION_TEST(SDK_API_TSHttpConnectIntercept)(RegressionTest *test, int /* atype */, int *pstatus)
8486 {
8487   *pstatus = REGRESSION_TEST_INPROGRESS;
8488 
8489   TSDebug(UTDBG_TAG, "Starting test TSHttpConnectIntercept");
8490 
8491   TSCont cont_test      = TSContCreate(cont_test_handler, TSMutexCreate());
8492   ConnectTestData *data = static_cast<ConnectTestData *>(TSmalloc(sizeof(ConnectTestData)));
8493   TSContDataSet(cont_test, data);
8494 
8495   data->test      = test;
8496   data->pstatus   = pstatus;
8497   data->magic     = MAGIC_ALIVE;
8498   data->test_case = TEST_CASE_CONNECT_ID1;
8499 
8500   /* Register to hook READ_REQUEST */
8501   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont_test);
8502 
8503   // Create a synthetic server which won't really listen on a socket port
8504   // It will be called by the Http SM with a VC
8505   data->os = synserver_create(SYNSERVER_DUMMY_PORT);
8506 
8507   data->browser = synclient_txn_create();
8508   data->request = generate_request(9);
8509 
8510   /* Now send a request to the OS via TS using TSHttpConnect */
8511 
8512   /* ip and log do not matter as it is used for logging only */
8513   sockaddr_in addr;
8514   ats_ip4_set(&addr, 1, 1);
8515   data->vc = TSHttpConnect(ats_ip_sa_cast(&addr));
8516   if (TSVConnClosedGet(data->vc)) {
8517     SDK_RPRINT(data->test, "TSHttpConnect", "TestCase 1", TC_FAIL, "Connect reported as closed immediately after open");
8518   }
8519   synclient_txn_send_request_to_vc(data->browser, data->request, data->vc);
8520 
8521   /* Wait until transaction is done */
8522   TSContScheduleOnPool(cont_test, 25, TS_THREAD_POOL_NET);
8523 
8524   return;
8525 }
8526 
EXCLUSIVE_REGRESSION_TEST(SDK_API_TSHttpConnectServerIntercept)8527 EXCLUSIVE_REGRESSION_TEST(SDK_API_TSHttpConnectServerIntercept)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8528 {
8529   *pstatus = REGRESSION_TEST_INPROGRESS;
8530 
8531   TSDebug(UTDBG_TAG, "Starting test TSHttpConnectServerIntercept");
8532 
8533   TSCont cont_test      = TSContCreate(cont_test_handler, TSMutexCreate());
8534   ConnectTestData *data = static_cast<ConnectTestData *>(TSmalloc(sizeof(ConnectTestData)));
8535   TSContDataSet(cont_test, data);
8536 
8537   data->test      = test;
8538   data->pstatus   = pstatus;
8539   data->magic     = MAGIC_ALIVE;
8540   data->test_case = TEST_CASE_CONNECT_ID2;
8541 
8542   /* Register to hook READ_REQUEST */
8543   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont_test);
8544 
8545   /* This is cool ! we can use the code written for the synthetic server and client in InkAPITest.cc */
8546   data->os = synserver_create(SYNSERVER_DUMMY_PORT);
8547 
8548   data->browser = synclient_txn_create();
8549   data->request = generate_request(10);
8550 
8551   /* Now send a request to the OS via TS using TSHttpConnect */
8552 
8553   /* ip and log do not matter as it is used for logging only */
8554   sockaddr_in addr;
8555   ats_ip4_set(&addr, 2, 2);
8556   data->vc = TSHttpConnect(ats_ip_sa_cast(&addr));
8557 
8558   synclient_txn_send_request_to_vc(data->browser, data->request, data->vc);
8559 
8560   /* Wait until transaction is done */
8561   TSContScheduleOnPool(cont_test, 25, TS_THREAD_POOL_NET);
8562 
8563   return;
8564 }
8565 
8566 ////////////////////////////////////////////////
8567 // SDK_API_OVERRIDABLE_CONFIGS
8568 //
8569 // Unit Test for API: TSHttpTxnConfigFind
8570 //                    TSHttpTxnConfigIntSet
8571 //                    TSHttpTxnConfigIntGet
8572 //                    TSHttpTxnConfigFloatSet
8573 //                    TSHttpTxnConfigFloatGet
8574 //                    TSHttpTxnConfigStringSet
8575 //                    TSHttpTxnConfigStringGet
8576 ////////////////////////////////////////////////
8577 
8578 // The order of these should be the same as TSOverridableConfigKey
8579 std::array<std::string_view, TS_CONFIG_LAST_ENTRY> SDK_Overridable_Configs = {
8580   {"proxy.config.url_remap.pristine_host_hdr",
8581    "proxy.config.http.chunking_enabled",
8582    "proxy.config.http.negative_caching_enabled",
8583    "proxy.config.http.negative_caching_lifetime",
8584    "proxy.config.http.cache.when_to_revalidate",
8585    "proxy.config.http.keep_alive_enabled_in",
8586    "proxy.config.http.keep_alive_enabled_out",
8587    "proxy.config.http.keep_alive_post_out",
8588    "proxy.config.http.server_session_sharing.match",
8589    "proxy.config.net.sock_recv_buffer_size_out",
8590    "proxy.config.net.sock_send_buffer_size_out",
8591    "proxy.config.net.sock_option_flag_out",
8592    "proxy.config.http.forward.proxy_auth_to_parent",
8593    "proxy.config.http.anonymize_remove_from",
8594    "proxy.config.http.anonymize_remove_referer",
8595    "proxy.config.http.anonymize_remove_user_agent",
8596    "proxy.config.http.anonymize_remove_cookie",
8597    "proxy.config.http.anonymize_remove_client_ip",
8598    "proxy.config.http.insert_client_ip",
8599    "proxy.config.http.response_server_enabled",
8600    "proxy.config.http.insert_squid_x_forwarded_for",
8601    "proxy.config.http.send_http11_requests",
8602    "proxy.config.http.cache.http",
8603    "proxy.config.http.cache.ignore_client_no_cache",
8604    "proxy.config.http.cache.ignore_client_cc_max_age",
8605    "proxy.config.http.cache.ims_on_client_no_cache",
8606    "proxy.config.http.cache.ignore_server_no_cache",
8607    "proxy.config.http.cache.cache_responses_to_cookies",
8608    "proxy.config.http.cache.ignore_authentication",
8609    "proxy.config.http.cache.cache_urls_that_look_dynamic",
8610    "proxy.config.http.cache.required_headers",
8611    "proxy.config.http.insert_request_via_str",
8612    "proxy.config.http.insert_response_via_str",
8613    "proxy.config.http.cache.heuristic_min_lifetime",
8614    "proxy.config.http.cache.heuristic_max_lifetime",
8615    "proxy.config.http.cache.guaranteed_min_lifetime",
8616    "proxy.config.http.cache.guaranteed_max_lifetime",
8617    "proxy.config.http.cache.max_stale_age",
8618    "proxy.config.http.keep_alive_no_activity_timeout_in",
8619    "proxy.config.http.keep_alive_no_activity_timeout_out",
8620    "proxy.config.http.transaction_no_activity_timeout_in",
8621    "proxy.config.http.transaction_no_activity_timeout_out",
8622    "proxy.config.http.transaction_active_timeout_out",
8623    "proxy.config.http.connect_attempts_max_retries",
8624    "proxy.config.http.connect_attempts_max_retries_dead_server",
8625    "proxy.config.http.connect_attempts_rr_retries",
8626    "proxy.config.http.connect_attempts_timeout",
8627    "proxy.config.http.post_connect_attempts_timeout",
8628    "proxy.config.http.down_server.cache_time",
8629    "proxy.config.http.down_server.abort_threshold",
8630    "proxy.config.http.doc_in_cache_skip_dns",
8631    "proxy.config.http.background_fill_active_timeout",
8632    "proxy.config.http.response_server_str",
8633    "proxy.config.http.cache.heuristic_lm_factor",
8634    "proxy.config.http.background_fill_completed_threshold",
8635    "proxy.config.net.sock_packet_mark_out",
8636    "proxy.config.net.sock_packet_tos_out",
8637    "proxy.config.http.insert_age_in_response",
8638    "proxy.config.http.chunking.size",
8639    "proxy.config.http.flow_control.enabled",
8640    "proxy.config.http.flow_control.low_water",
8641    "proxy.config.http.flow_control.high_water",
8642    "proxy.config.http.cache.range.lookup",
8643    "proxy.config.http.default_buffer_size",
8644    "proxy.config.http.default_buffer_water_mark",
8645    "proxy.config.http.request_header_max_size",
8646    "proxy.config.http.response_header_max_size",
8647    "proxy.config.http.negative_revalidating_enabled",
8648    "proxy.config.http.negative_revalidating_lifetime",
8649    "proxy.config.ssl.hsts_max_age",
8650    "proxy.config.ssl.hsts_include_subdomains",
8651    "proxy.config.http.cache.open_read_retry_time",
8652    "proxy.config.http.cache.max_open_read_retries",
8653    "proxy.config.http.cache.range.write",
8654    "proxy.config.http.post.check.content_length.enabled",
8655    "proxy.config.http.global_user_agent_header",
8656    "proxy.config.http.auth_server_session_private",
8657    "proxy.config.http.slow.log.threshold",
8658    "proxy.config.http.cache.generation",
8659    "proxy.config.body_factory.template_base",
8660    "proxy.config.http.cache.open_write_fail_action",
8661    "proxy.config.http.number_of_redirections",
8662    "proxy.config.http.cache.max_open_write_retries",
8663    "proxy.config.http.redirect_use_orig_cache_key",
8664    "proxy.config.http.attach_server_session_to_client",
8665    "proxy.config.websocket.no_activity_timeout",
8666    "proxy.config.websocket.active_timeout",
8667    "proxy.config.http.uncacheable_requests_bypass_parent",
8668    "proxy.config.http.parent_proxy.total_connect_attempts",
8669    "proxy.config.http.transaction_active_timeout_in",
8670    "proxy.config.srv_enabled",
8671    "proxy.config.http.forward_connect_method",
8672    "proxy.config.ssl.client.cert.filename",
8673    "proxy.config.ssl.client.cert.path",
8674    "proxy.config.http.parent_proxy.mark_down_hostdb",
8675    "proxy.config.http.cache.ignore_accept_mismatch",
8676    "proxy.config.http.cache.ignore_accept_language_mismatch",
8677    "proxy.config.http.cache.ignore_accept_encoding_mismatch",
8678    "proxy.config.http.cache.ignore_accept_charset_mismatch",
8679    "proxy.config.http.parent_proxy.fail_threshold",
8680    "proxy.config.http.parent_proxy.retry_time",
8681    "proxy.config.http.parent_proxy.per_parent_connect_attempts",
8682    "proxy.config.http.parent_proxy.connect_attempts_timeout",
8683    "proxy.config.http.normalize_ae",
8684    "proxy.config.http.insert_forwarded",
8685    "proxy.config.http.proxy_protocol_out",
8686    "proxy.config.http.allow_multi_range",
8687    "proxy.config.http.request_buffer_enabled",
8688    "proxy.config.http.allow_half_open",
8689    OutboundConnTrack::CONFIG_VAR_MIN,
8690    OutboundConnTrack::CONFIG_VAR_MAX,
8691    OutboundConnTrack::CONFIG_VAR_MATCH,
8692    "proxy.config.ssl.client.verify.server",
8693    "proxy.config.ssl.client.verify.server.policy",
8694    "proxy.config.ssl.client.verify.server.properties",
8695    "proxy.config.ssl.client.sni_policy",
8696    "proxy.config.ssl.client.private_key.filename",
8697    "proxy.config.ssl.client.CA.cert.filename",
8698    "proxy.config.hostdb.ip_resolve",
8699    "proxy.config.http.connect.dead.policy"}};
8700 
8701 extern ClassAllocator<HttpSM> httpSMAllocator;
8702 
REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)8703 REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8704 {
8705   TSOverridableConfigKey key;
8706   TSRecordDataType type;
8707   HttpSM *s      = THREAD_ALLOC(httpSMAllocator, this_thread());
8708   bool success   = true;
8709   TSHttpTxn txnp = reinterpret_cast<TSHttpTxn>(s);
8710   InkRand generator(17);
8711   TSMgmtInt ival_read, ival_rand;
8712   TSMgmtFloat fval_read, fval_rand;
8713   const char *sval_read;
8714   const char *test_string = "The Apache Traffic Server";
8715   int len;
8716 
8717   s->init();
8718 
8719   *pstatus = REGRESSION_TEST_INPROGRESS;
8720   for (int i = 0; i < static_cast<int>(SDK_Overridable_Configs.size()); ++i) {
8721     std::string_view conf{SDK_Overridable_Configs[i]};
8722 
8723     if (TS_SUCCESS == TSHttpTxnConfigFind(conf.data(), -1, &key, &type)) {
8724       if (key != i) {
8725         SDK_RPRINT(test, "TSHttpTxnConfigFind", "TestCase1", TC_FAIL, "Failed on %s, expected %d, got %d", conf.data(), i, key);
8726         success = false;
8727         continue;
8728       }
8729     } else {
8730       SDK_RPRINT(test, "TSHttpTxnConfigFind", "TestCase1", TC_FAIL, "Call returned unexpected TS_ERROR for %s", conf.data());
8731       success = false;
8732       continue;
8733     }
8734 
8735     if (TS_SUCCESS == TSHttpTxnConfigFind(conf.data(), conf.size(), &key, &type)) {
8736       if (key != i) {
8737         SDK_RPRINT(test, "TSHttpTxnConfigFind", "TestCase1", TC_FAIL, "Failed on %s, expected %d, got %d", conf.data(), i, key);
8738         success = false;
8739         continue;
8740       }
8741     } else {
8742       SDK_RPRINT(test, "TSHttpTxnConfigFind", "TestCase1", TC_FAIL, "Call returned unexpected TS_ERROR for %s", conf.data());
8743       success = false;
8744       continue;
8745     }
8746 
8747     // Now check the getters / setters
8748     switch (type) {
8749     case TS_RECORDDATATYPE_INT:
8750       ival_rand = generator.random() % 126; // to fit in a signed byte
8751       TSHttpTxnConfigIntSet(txnp, key, ival_rand);
8752       TSHttpTxnConfigIntGet(txnp, key, &ival_read);
8753       if (ival_rand != ival_read) {
8754         SDK_RPRINT(test, "TSHttpTxnConfigIntSet", "TestCase1", TC_FAIL, "Failed on %s, %d != %d", conf.data(), ival_read,
8755                    ival_rand);
8756         success = false;
8757         continue;
8758       }
8759       break;
8760 
8761     case TS_RECORDDATATYPE_FLOAT:
8762       fval_rand = generator.random();
8763       TSHttpTxnConfigFloatSet(txnp, key, fval_rand);
8764       TSHttpTxnConfigFloatGet(txnp, key, &fval_read);
8765       if (fval_rand != fval_read) {
8766         SDK_RPRINT(test, "TSHttpTxnConfigFloatSet", "TestCase1", TC_FAIL, "Failed on %s, %f != %f", conf.data(), fval_read,
8767                    fval_rand);
8768         success = false;
8769         continue;
8770       }
8771       break;
8772 
8773     case TS_RECORDDATATYPE_STRING:
8774       TSHttpTxnConfigStringSet(txnp, key, test_string, -1);
8775       TSHttpTxnConfigStringGet(txnp, key, &sval_read, &len);
8776       if (test_string != sval_read) {
8777         SDK_RPRINT(test, "TSHttpTxnConfigStringSet", "TestCase1", TC_FAIL, "Failed on %s, %s != %s", conf.data(), sval_read,
8778                    test_string);
8779         success = false;
8780         continue;
8781       }
8782       break;
8783 
8784     default:
8785       break;
8786     }
8787   }
8788 
8789   s->destroy();
8790   if (success) {
8791     *pstatus = REGRESSION_TEST_PASSED;
8792     SDK_RPRINT(test, "TSHttpTxnConfigFind", "TestCase1", TC_PASS, "ok");
8793     SDK_RPRINT(test, "TSHttpTxnConfigIntSet", "TestCase1", TC_PASS, "ok");
8794     SDK_RPRINT(test, "TSHttpTxnConfigFloatSet", "TestCase1", TC_PASS, "ok");
8795     SDK_RPRINT(test, "TSHttpTxnConfigStringSet", "TestCase1", TC_PASS, "ok");
8796   } else {
8797     *pstatus = REGRESSION_TEST_FAILED;
8798   }
8799 
8800   return;
8801 }
8802 
8803 ////////////////////////////////////////////////
8804 // SDK_API_TXN_HTTP_INFO_INFO_GET
8805 //
8806 // Unit Test for API: TSHttpTxnInfoIntGet
8807 ////////////////////////////////////////////////
8808 
REGRESSION_TEST(SDK_API_TXN_HTTP_INFO_GET)8809 REGRESSION_TEST(SDK_API_TXN_HTTP_INFO_GET)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8810 {
8811   HttpSM *s      = THREAD_ALLOC(httpSMAllocator, this_thread());
8812   bool success   = true;
8813   TSHttpTxn txnp = reinterpret_cast<TSHttpTxn>(s);
8814   TSMgmtInt ival_read;
8815 
8816   s->init();
8817 
8818   *pstatus          = REGRESSION_TEST_INPROGRESS;
8819   HttpCacheSM *c_sm = &(s->get_cache_sm());
8820   c_sm->set_readwhilewrite_inprogress(true);
8821   c_sm->set_open_read_tries(5);
8822   c_sm->set_open_write_tries(8);
8823 
8824   TSHttpTxnInfoIntGet(txnp, TS_TXN_INFO_CACHE_HIT_RWW, &ival_read);
8825   if (ival_read == 0) {
8826     SDK_RPRINT(test, "TSHttpTxnInfoIntGet", "TestCase1", TC_FAIL, "Failed on %d, %d != %d", TS_TXN_INFO_CACHE_HIT_RWW, ival_read,
8827                1);
8828     success = false;
8829   }
8830 
8831   TSHttpTxnInfoIntGet(txnp, TS_TXN_INFO_CACHE_OPEN_READ_TRIES, &ival_read);
8832   if (ival_read != 5) {
8833     SDK_RPRINT(test, "TSHttpTxnInfoIntGet", "TestCase1", TC_FAIL, "Failed on %d, %d != %d", TS_TXN_INFO_CACHE_HIT_RWW, ival_read,
8834                5);
8835     success = false;
8836   }
8837 
8838   TSHttpTxnInfoIntGet(txnp, TS_TXN_INFO_CACHE_OPEN_WRITE_TRIES, &ival_read);
8839   if (ival_read != 8) {
8840     SDK_RPRINT(test, "TSHttpTxnInfoIntGet", "TestCase1", TC_FAIL, "Failed on %d, %d != %d", TS_TXN_INFO_CACHE_HIT_RWW, ival_read,
8841                8);
8842     success = false;
8843   }
8844 
8845   s->destroy();
8846   if (success) {
8847     *pstatus = REGRESSION_TEST_PASSED;
8848     SDK_RPRINT(test, "TSHttpTxnInfoIntGet", "TestCase1", TC_PASS, "ok");
8849   } else {
8850     *pstatus = REGRESSION_TEST_FAILED;
8851   }
8852 
8853   return;
8854 }
8855 
8856 ////////////////////////////////////////////////
8857 // SDK_API_ENCODING
8858 //
8859 // Unit Test for API: TSStringPercentEncode
8860 //                    TSUrlPercentEncode
8861 //                    TSStringPercentDecode
8862 ////////////////////////////////////////////////
8863 
REGRESSION_TEST(SDK_API_ENCODING)8864 REGRESSION_TEST(SDK_API_ENCODING)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8865 {
8866   const char *url = "http://www.example.com/foo?fie= \"#%<>[]\\^`{}~&bar={test}&fum=Apache Traffic Server";
8867   const char *url_encoded =
8868     "http://www.example.com/foo?fie=%20%22%23%25%3C%3E%5B%5D%5C%5E%60%7B%7D%7E&bar=%7Btest%7D&fum=Apache%20Traffic%20Server";
8869   const char *url_base64 =
8870     "aHR0cDovL3d3dy5leGFtcGxlLmNvbS9mb28/ZmllPSAiIyU8PltdXF5ge31+JmJhcj17dGVzdH0mZnVtPUFwYWNoZSBUcmFmZmljIFNlcnZlcg==";
8871   const char *url2 = "http://www.example.com/"; // No Percent encoding necessary
8872   const char *url3 = "https://www.thisisoneexampleofastringoflengtheightyasciilowercasecharacters.com/";
8873   char buf[1024];
8874   size_t length;
8875   bool success = true;
8876 
8877   if (TS_SUCCESS != TSStringPercentEncode(url, strlen(url), buf, sizeof(buf), &length, nullptr)) {
8878     SDK_RPRINT(test, "TSStringPercentEncode", "TestCase1", TC_FAIL, "Failed on %s", url);
8879     success = false;
8880   } else {
8881     if (strcmp(buf, url_encoded)) {
8882       SDK_RPRINT(test, "TSStringPercentEncode", "TestCase1", TC_FAIL, "Failed on %s != %s", buf, url_encoded);
8883       success = false;
8884     } else {
8885       SDK_RPRINT(test, "TSStringPercentEncode", "TestCase1", TC_PASS, "ok");
8886     }
8887   }
8888 
8889   if (TS_SUCCESS != TSStringPercentEncode(url2, strlen(url2), buf, sizeof(buf), &length, nullptr)) {
8890     SDK_RPRINT(test, "TSStringPercentEncode", "TestCase2", TC_FAIL, "Failed on %s", url2);
8891     success = false;
8892   } else {
8893     if (strcmp(buf, url2)) {
8894       SDK_RPRINT(test, "TSStringPercentEncode", "TestCase2", TC_FAIL, "Failed on %s != %s", buf, url2);
8895       success = false;
8896     } else {
8897       SDK_RPRINT(test, "TSStringPercentEncode", "TestCase2", TC_PASS, "ok");
8898     }
8899   }
8900 
8901   if (TS_SUCCESS != TSStringPercentDecode(url_encoded, strlen(url_encoded), buf, sizeof(buf), &length)) {
8902     SDK_RPRINT(test, "TSStringPercentDecode", "TestCase1", TC_FAIL, "Failed on %s", url_encoded);
8903     success = false;
8904   } else {
8905     if (length != strlen(url) || strcmp(buf, url)) {
8906       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase1", TC_FAIL, "Failed on %s != %s", buf, url);
8907       success = false;
8908     } else {
8909       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase1", TC_PASS, "ok");
8910     }
8911   }
8912 
8913   if (TS_SUCCESS != TSStringPercentDecode(url2, strlen(url2), buf, sizeof(buf), &length)) {
8914     SDK_RPRINT(test, "TSStringPercentDecode", "TestCase2", TC_FAIL, "Failed on %s", url2);
8915     success = false;
8916   } else {
8917     if (length != strlen(url2) || strcmp(buf, url2)) {
8918       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase2", TC_FAIL, "Failed on %s != %s", buf, url2);
8919       success = false;
8920     } else {
8921       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase2", TC_PASS, "ok");
8922     }
8923   }
8924 
8925   // test to verify TSStringPercentDecode does not write past the end of the
8926   // buffer
8927   const size_t buf_len = strlen(url3) + 1; // 81
8928   memcpy(buf, url3, buf_len - 1);
8929   const char canary = 0xFF;
8930   buf[buf_len - 1]  = canary;
8931 
8932   const char *url3_clipped = "https://www.thisisoneexampleofastringoflengtheightyasciilowercasecharacters.com";
8933   if (TS_SUCCESS != TSStringPercentDecode(buf, buf_len - 1, buf, buf_len - 1, &length)) {
8934     SDK_RPRINT(test, "TSStringPercentDecode", "TestCase3", TC_FAIL, "Failed on %s", url3);
8935     success = false;
8936   } else {
8937     if (memcmp(buf + buf_len - 1, &canary, 1)) { // Overwrite
8938       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase3", TC_FAIL, "Failed on %s overwrites buffer", url3);
8939       success = false;
8940     } else if (length != strlen(url3_clipped) || strcmp(buf, url3_clipped)) {
8941       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase3", TC_FAIL, "Failed on %s != %s", buf, url3_clipped);
8942       success = false;
8943     } else {
8944       SDK_RPRINT(test, "TSStringPercentDecode", "TestCase3", TC_PASS, "ok");
8945     }
8946   }
8947 
8948   if (TS_SUCCESS != TSBase64Encode(url, strlen(url), buf, sizeof(buf), &length)) {
8949     SDK_RPRINT(test, "TSBase64Encode", "TestCase1", TC_FAIL, "Failed on %s", url);
8950     success = false;
8951   } else {
8952     if (length != strlen(url_base64) || strcmp(buf, url_base64)) {
8953       SDK_RPRINT(test, "TSBase64Encode", "TestCase1", TC_FAIL, "Failed on %s != %s", buf, url_base64);
8954       success = false;
8955     } else {
8956       SDK_RPRINT(test, "TSBase64Encode", "TestCase1", TC_PASS, "ok");
8957     }
8958   }
8959 
8960   if (TS_SUCCESS != TSBase64Decode(url_base64, strlen(url_base64), reinterpret_cast<unsigned char *>(buf), sizeof(buf), &length)) {
8961     SDK_RPRINT(test, "TSBase64Decode", "TestCase1", TC_FAIL, "Failed on %s", url_base64);
8962     success = false;
8963   } else {
8964     if (length != strlen(url) || strcmp(buf, url)) {
8965       SDK_RPRINT(test, "TSBase64Decode", "TestCase1", TC_FAIL, "Failed on %s != %s", buf, url);
8966       success = false;
8967     } else {
8968       SDK_RPRINT(test, "TSBase64Decode", "TestCase1", TC_PASS, "ok");
8969     }
8970   }
8971 
8972   *pstatus = success ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED;
8973 
8974   return;
8975 }
8976 
8977 ////////////////////////////////////////////////
8978 // SDK_API_DEBUG_NAME_LOOKUPS
8979 //
8980 // Unit Test for API: TSHttpServerStateNameLookup
8981 //                    TSHttpHookNameLookup
8982 //                    TSHttpEventNameLookup
8983 ////////////////////////////////////////////////
8984 
REGRESSION_TEST(SDK_API_DEBUG_NAME_LOOKUPS)8985 REGRESSION_TEST(SDK_API_DEBUG_NAME_LOOKUPS)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
8986 {
8987   bool success            = true;
8988   const char state_name[] = "INACTIVE_TIMEOUT";
8989   const char hook_name[]  = "TS_HTTP_READ_RESPONSE_HDR_HOOK";
8990   const char event_name[] = "TS_EVENT_IMMEDIATE";
8991   const char *str;
8992 
8993   *pstatus = REGRESSION_TEST_INPROGRESS;
8994 
8995   str = TSHttpServerStateNameLookup(TS_SRVSTATE_INACTIVE_TIMEOUT);
8996   if ((strlen(str) != strlen(state_name) || strcmp(str, state_name))) {
8997     SDK_RPRINT(test, "TSHttpServerStateNameLookup", "TestCase1", TC_FAIL, "Failed on %d, expected %s, got %s",
8998                TS_SRVSTATE_INACTIVE_TIMEOUT, state_name, str);
8999     success = false;
9000   } else {
9001     SDK_RPRINT(test, "TSHttpServerStateNameLookup", "TestCase1", TC_PASS, "ok");
9002   }
9003 
9004   str = TSHttpHookNameLookup(TS_HTTP_READ_RESPONSE_HDR_HOOK);
9005   if ((strlen(str) != strlen(hook_name) || strcmp(str, hook_name))) {
9006     SDK_RPRINT(test, "TSHttpHookNameLookup", "TestCase1", TC_FAIL, "Failed on %d, expected %s, got %s",
9007                TS_HTTP_READ_RESPONSE_HDR_HOOK, hook_name, str);
9008     success = false;
9009   } else {
9010     SDK_RPRINT(test, "TSHttpHookNameLookup", "TestCase1", TC_PASS, "ok");
9011   }
9012 
9013   str = TSHttpEventNameLookup(TS_EVENT_IMMEDIATE);
9014   if (strstr(str, event_name) == nullptr) {
9015     SDK_RPRINT(test, "TSHttpEventNameLookup", "TestCase1", TC_FAIL, "Failed on %d, expected %s to be within %s", TS_EVENT_IMMEDIATE,
9016                event_name, str);
9017     success = false;
9018   } else {
9019     SDK_RPRINT(test, "TSHttpEventNameLookup", "TestCase1", TC_PASS, "ok");
9020   }
9021 
9022   *pstatus = success ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED;
9023 
9024   return;
9025 }
9026 
9027 ////////////////////////////////////////////////
9028 // SDK_API_UUID
9029 //
9030 // Unit Test for API: TSUuidCreate
9031 //                    TSUuidDestroy
9032 //                    TSUuidCopy
9033 //                    TSUuidInitialize
9034 //                    TSProcessUuidGet
9035 //                    TSUuidStringGet
9036 //                    TSUuidVersionGet
9037 //                    TSUuidStringParse
9038 ////////////////////////////////////////////////
9039 #include "tscore/ink_uuid.h"
9040 
REGRESSION_TEST(SDK_API_UUID)9041 REGRESSION_TEST(SDK_API_UUID)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
9042 {
9043   TSUuid machine, uuid;
9044   const char *str1;
9045   const char *str2;
9046   static const char uuid_v1[] = "5de5f9ec-30f4-11e6-a073-002590a33e4e";
9047   static const char uuid_v4[] = "0e95fe5f-295a-401d-9ae4-eb32756d73cb";
9048 
9049   *pstatus = REGRESSION_TEST_INPROGRESS;
9050 
9051   // Test TSProcessUuidGet(), should just return a non-NULL pointer now.
9052   machine = TSProcessUuidGet();
9053   if (!machine) {
9054     SDK_RPRINT(test, "TSProcessUuidGet", "TestCase1", TC_FAIL, "Returned a NULL pointer");
9055     *pstatus = REGRESSION_TEST_FAILED;
9056     return;
9057   } else if (!(reinterpret_cast<ATSUuid *>(machine))->valid()) {
9058     SDK_RPRINT(test, "TSProcessUuidGet", "TestCase2", TC_FAIL, "Returned an invalid UUID object");
9059     *pstatus = REGRESSION_TEST_FAILED;
9060     return;
9061   } else {
9062     SDK_RPRINT(test, "TSProcessUuidGet", "TestCase1", TC_PASS, "ok");
9063     SDK_RPRINT(test, "TSProcessUuidGet", "TestCase2", TC_PASS, "ok");
9064   }
9065 
9066   // Test TSUuidStringGet, should return a random string (so can't check the string value itself)
9067   str1 = TSUuidStringGet(machine);
9068   if (!str1 || (TS_UUID_STRING_LEN != strlen(str1))) {
9069     SDK_RPRINT(test, "TSUuidStringGet", "TestCase1", TC_FAIL, "Did not return a valid UUID string representation");
9070     *pstatus = REGRESSION_TEST_FAILED;
9071     return;
9072   } else {
9073     SDK_RPRINT(test, "TSUuidStringGet", "TestCase1", TC_PASS, "ok");
9074   }
9075 
9076   // Test TSUuidCreate
9077   if (!(uuid = TSUuidCreate())) {
9078     SDK_RPRINT(test, "TSUuidCreate", "TestCase1", TC_FAIL, "Failed to create a UUID object");
9079     *pstatus = REGRESSION_TEST_FAILED;
9080     return;
9081   } else {
9082     SDK_RPRINT(test, "TSUuidCreate", "TestCase1", TC_PASS, "ok");
9083     if (TS_SUCCESS != TSUuidInitialize(uuid, TS_UUID_V4)) {
9084       SDK_RPRINT(test, "TSUuidInitialize", "TestCase1", TC_FAIL, "Failed to Initialize a V4 UUID");
9085       *pstatus = REGRESSION_TEST_FAILED;
9086       goto cleanup;
9087     } else {
9088       SDK_RPRINT(test, "TSUuidInitialize", "TestCase1", TC_PASS, "ok");
9089     }
9090   }
9091 
9092   // Test TSUuidVersion
9093   if (TS_UUID_V4 != TSUuidVersionGet(uuid)) {
9094     SDK_RPRINT(test, "TSUuidVersionGet", "TestCase1", TC_FAIL, "Failed to get the UUID version");
9095     *pstatus = REGRESSION_TEST_FAILED;
9096     goto cleanup;
9097   } else {
9098     SDK_RPRINT(test, "TSUuidVersionGet", "TestCase1", TC_PASS, "ok");
9099   }
9100 
9101   // Test TSUuidCopy
9102   if (TS_SUCCESS != TSUuidCopy(uuid, machine)) {
9103     SDK_RPRINT(test, "TSUuidCopy", "TestCase1", TC_FAIL, "Failed to copy the Machine UUID object");
9104     *pstatus = REGRESSION_TEST_FAILED;
9105     goto cleanup;
9106   } else {
9107     SDK_RPRINT(test, "TSUuidCopy", "TestCase1", TC_PASS, "ok");
9108     str2 = TSUuidStringGet(uuid);
9109     if (!str2 || (TS_UUID_STRING_LEN != strlen(str2)) || strcmp(str1, str2)) {
9110       SDK_RPRINT(test, "TSUuidCopy", "TestCase2", TC_FAIL, "The copied UUID strings are not identical");
9111       *pstatus = REGRESSION_TEST_FAILED;
9112       goto cleanup;
9113     } else {
9114       SDK_RPRINT(test, "TSUuidCopy", "TestCase2", TC_PASS, "ok");
9115     }
9116   }
9117 
9118   // Test TSUuidInitialize again, make sure they take effect when called multiple times
9119   if (TS_SUCCESS != TSUuidInitialize(uuid, TS_UUID_V4)) {
9120     SDK_RPRINT(test, "TSUuidInitialize", "TestCase2", TC_FAIL, "Failed to re-initialize the UUID object");
9121     *pstatus = REGRESSION_TEST_FAILED;
9122     goto cleanup;
9123   } else {
9124     SDK_RPRINT(test, "TSUuidInitialize", "TestCase2", TC_PASS, "ok");
9125     str2 = TSUuidStringGet(uuid);
9126     if (!str2 || (TS_UUID_STRING_LEN != strlen(str2)) || !strcmp(str1, str2)) {
9127       SDK_RPRINT(test, "TSUuidInitialize", "TestCase3", TC_FAIL, "The re-initialized string is the same as before");
9128       *pstatus = REGRESSION_TEST_FAILED;
9129       goto cleanup;
9130     } else {
9131       SDK_RPRINT(test, "TSUuidInitialize", "TestCase3", TC_PASS, "ok");
9132     }
9133   }
9134 
9135   // Test TSUuidStringParse
9136   if ((TS_SUCCESS != TSUuidStringParse(uuid, uuid_v1)) || (TS_UUID_V1 != TSUuidVersionGet(uuid))) {
9137     SDK_RPRINT(test, "TSUuidStringParse", "TestCase1", TC_FAIL, "Failed to parse the UUID v1 string");
9138     *pstatus = REGRESSION_TEST_FAILED;
9139     goto cleanup;
9140   } else {
9141     SDK_RPRINT(test, "TSUuidStringParse", "TestCase1", TC_PASS, "ok");
9142     str1 = TSUuidStringGet(uuid);
9143     if (!str1 || (TS_UUID_STRING_LEN != strlen(str1)) || strcmp(str1, uuid_v1)) {
9144       SDK_RPRINT(test, "TSUuidStringString", "TestCase2", TC_FAIL, "The parse UUID v1 string does not match the original");
9145       *pstatus = REGRESSION_TEST_FAILED;
9146       goto cleanup;
9147     } else {
9148       SDK_RPRINT(test, "TSUuidStringParse", "TestCase2", TC_PASS, "ok");
9149     }
9150   }
9151   if ((TS_SUCCESS != TSUuidStringParse(uuid, uuid_v4)) || (TS_UUID_V4 != TSUuidVersionGet(uuid))) {
9152     SDK_RPRINT(test, "TSUuidStringParse", "TestCase3", TC_FAIL, "Failed to parse the UUID v4 string");
9153     *pstatus = REGRESSION_TEST_FAILED;
9154     goto cleanup;
9155   } else {
9156     SDK_RPRINT(test, "TSUuidStringParse", "TestCase3", TC_PASS, "ok");
9157     str1 = TSUuidStringGet(uuid);
9158     if (!str1 || (TS_UUID_STRING_LEN != strlen(str1)) || strcmp(str1, uuid_v4)) {
9159       SDK_RPRINT(test, "TSUuidStringParse", "TestCase4", TC_FAIL, "The parse UUID v4 string does not match the original");
9160       *pstatus = REGRESSION_TEST_FAILED;
9161       goto cleanup;
9162     } else {
9163       SDK_RPRINT(test, "TSUuidStringParse", "TestCase4", TC_PASS, "ok");
9164     }
9165   }
9166 
9167   *pstatus = REGRESSION_TEST_PASSED;
9168 
9169 cleanup:
9170   TSUuidDestroy(uuid);
9171 
9172   return;
9173 }
9174 
REGRESSION_TEST(SDK_API_TSSslServerContextCreate)9175 REGRESSION_TEST(SDK_API_TSSslServerContextCreate)(RegressionTest *test, int level, int *pstatus)
9176 {
9177   TSSslContext ctx;
9178 
9179   // See TS-4769: TSSslServerContextCreate always returns null.
9180   ctx = TSSslServerContextCreate(nullptr, nullptr, nullptr);
9181 
9182   *pstatus = ctx ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED;
9183   TSSslContextDestroy(ctx);
9184 }
9185 
REGRESSION_TEST(SDK_API_TSStatCreate)9186 REGRESSION_TEST(SDK_API_TSStatCreate)(RegressionTest *test, int level, int *pstatus)
9187 {
9188   const char name[] = "regression.test.metric";
9189   int id;
9190 
9191   TestBox box(test, pstatus);
9192 
9193   box = REGRESSION_TEST_PASSED;
9194 
9195   if (TSStatFindName(name, &id) == TS_SUCCESS) {
9196     box.check(id >= 0, "TSStatFind(%s) failed with bogus ID %d", name, id);
9197   } else {
9198     id = TSStatCreate(name, TS_RECORDDATATYPE_COUNTER, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
9199     box.check(id != TS_ERROR, "TSStatCreate(%s) failed with %d", name, id);
9200   }
9201 
9202   TSStatIntSet(id, getpid());
9203   TSStatIntIncrement(id, 1);
9204   TSStatIntIncrement(id, 1);
9205 
9206   TSMgmtInt value    = TSStatIntGet(id);
9207   TSMgmtInt expected = getpid() + 2;
9208 
9209   box.check(expected >= value, "TSStatIntGet(%s) gave %" PRId64 ", expected at least %" PRId64, name, value, expected);
9210 }
9211