1 /** @file
2   Licensed to the Apache Software Foundation (ASF) under one
3   or more contributor license agreements.  See the NOTICE file
4   distributed with this work for additional information
5   regarding copyright ownership.  The ASF licenses this file
6   to you under the Apache License, Version 2.0 (the
7   "License"); you may not use this file except in compliance
8   with the License.  You may obtain a copy of the License at
9 
10       http://www.apache.org/licenses/LICENSE-2.0
11 
12   Unless required by applicable law or agreed to in writing, software
13   distributed under the License is distributed on an "AS IS" BASIS,
14   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   See the License for the specific language governing permissions and
16   limitations under the License.
17  */
18 
19 #include "util.h"
20 
21 #include "Config.h"
22 #include "Data.h"
23 
24 void
shutdown(TSCont const contp,Data * const data)25 shutdown(TSCont const contp, Data *const data)
26 {
27   DEBUG_LOG("shutting down transaction");
28   TSContDataSet(contp, nullptr);
29   delete data;
30   TSContDestroy(contp);
31 }
32 
33 void
abort(TSCont const contp,Data * const data)34 abort(TSCont const contp, Data *const data)
35 {
36   DEBUG_LOG("aborting transaction");
37   TSContDataSet(contp, nullptr);
38   data->m_upstream.abort();
39   data->m_dnstream.abort();
40   delete data;
41   TSContDestroy(contp);
42 }
43 
44 // create and issue a block request
45 bool
request_block(TSCont contp,Data * const data)46 request_block(TSCont contp, Data *const data)
47 {
48   // ensure no upstream connection
49   if (data->m_upstream.m_read.isOpen()) {
50     ERROR_LOG("Block request already in flight!");
51     return false;
52   }
53 
54   switch (data->m_blockstate) {
55   case BlockState::Pending:
56   case BlockState::PendingInt:
57   case BlockState::PendingRef:
58     break;
59   default:
60     ERROR_LOG("request_block called with non Pending* state!");
61     return false;
62     break;
63   }
64 
65   int64_t const blockbeg = (data->m_config->m_blockbytes * data->m_blocknum);
66   Range blockbe(blockbeg, blockbeg + data->m_config->m_blockbytes);
67 
68   char rangestr[1024];
69   int rangelen      = sizeof(rangestr);
70   bool const rpstat = blockbe.toStringClosed(rangestr, &rangelen);
71   TSAssert(rpstat);
72 
73   DEBUG_LOG("requestBlock: %s", rangestr);
74 
75   // reuse the incoming client header, just change the range
76   HttpHeader header(data->m_req_hdrmgr.m_buffer, data->m_req_hdrmgr.m_lochdr);
77 
78   // add/set sub range key and add slicer tag
79   bool const rangestat = header.setKeyVal(TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rangestr, rangelen);
80 
81   if (!rangestat) {
82     ERROR_LOG("Error trying to set range request header %s", rangestr);
83     return false;
84   }
85 
86   // create virtual connection back into ATS
87   TSVConn const upvc = TSHttpConnectWithPluginId((sockaddr *)&data->m_client_ip, PLUGIN_NAME, 0);
88 
89   int const hlen = TSHttpHdrLengthGet(header.m_buffer, header.m_lochdr);
90 
91   // set up connection with the HttpConnect server
92   data->m_upstream.setupConnection(upvc);
93   data->m_upstream.setupVioWrite(contp, hlen);
94 
95   // Send full request
96   TSHttpHdrPrint(header.m_buffer, header.m_lochdr, data->m_upstream.m_write.m_iobuf);
97   TSVIOReenable(data->m_upstream.m_write.m_vio);
98 
99   if (TSIsDebugTagSet(PLUGIN_NAME)) {
100     std::string const headerstr(header.toString());
101     DEBUG_LOG("Headers\n%s", headerstr.c_str());
102   }
103 
104   // get ready for data back from the server
105   data->m_upstream.setupVioRead(contp, INT64_MAX);
106 
107   // anticipate the next server response header
108   TSHttpParserClear(data->m_http_parser);
109   data->m_resp_hdrmgr.resetHeader();
110 
111   data->m_blockexpected              = 0;
112   data->m_blockconsumed              = 0;
113   data->m_server_block_header_parsed = false;
114 
115   switch (data->m_blockstate) {
116   case BlockState::Pending:
117     data->m_blockstate = BlockState::Active;
118     break;
119   case BlockState::PendingInt:
120     data->m_blockstate = BlockState::ActiveInt;
121     header.removeKey(X_CRR_IMS_HEADER.data(), X_CRR_IMS_HEADER.size());
122     break;
123   case BlockState::PendingRef:
124     data->m_blockstate = BlockState::ActiveRef;
125     header.removeKey(X_CRR_IMS_HEADER.data(), X_CRR_IMS_HEADER.size());
126     break;
127   default:
128     ERROR_LOG("Invalid blockstate");
129     break;
130   }
131 
132   return true;
133 }
134 
135 bool
reader_avail_more_than(TSIOBufferReader const reader,int64_t bytes)136 reader_avail_more_than(TSIOBufferReader const reader, int64_t bytes)
137 {
138   TSIOBufferBlock block = TSIOBufferReaderStart(reader);
139 
140   if (nullptr == block) {
141     return false;
142   }
143 
144   while (nullptr != block) {
145     int64_t const blockbytes = TSIOBufferBlockReadAvail(block, reader);
146     if (bytes < blockbytes) {
147       return true;
148     } else {
149       bytes -= blockbytes;
150     }
151 
152     block = TSIOBufferBlockNext(block);
153   }
154 
155   return false;
156 }
157