xref: /trafficserver/plugins/multiplexer/post.cc (revision b0d78e49)
1 /** @file
2 
3   Multiplexes request to other origins.
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 #include <cassert>
24 #include <limits>
25 
26 #include "post.h"
27 
28 #ifndef PLUGIN_TAG
29 #error Please define a PLUGIN_TAG before including this file.
30 #endif
31 
~PostState()32 PostState::~PostState()
33 {
34   if (buffer != nullptr) {
35     TSIOBufferDestroy(buffer);
36     buffer = nullptr;
37   }
38 }
39 
PostState(Requests & r)40 PostState::PostState(Requests &r) : buffer(nullptr), reader(nullptr), vio(nullptr)
41 {
42   assert(!r.empty());
43   requests.swap(r);
44 }
45 
46 static void
postTransform(const TSCont c,PostState & s)47 postTransform(const TSCont c, PostState &s)
48 {
49   assert(c != nullptr);
50 
51   const TSVConn vconnection = TSTransformOutputVConnGet(c);
52   assert(vconnection != nullptr);
53 
54   const TSVIO vio = TSVConnWriteVIOGet(c);
55   assert(vio != nullptr);
56 
57   if (!s.buffer) {
58     s.buffer = TSIOBufferCreate();
59     assert(s.buffer != nullptr);
60 
61     const TSIOBufferReader reader = TSIOBufferReaderAlloc(s.buffer);
62     assert(reader != nullptr);
63 
64     s.reader = TSIOBufferReaderClone(reader);
65     assert(s.reader != nullptr);
66 
67     s.vio = TSVConnWrite(vconnection, c, reader, std::numeric_limits<int64_t>::max());
68     assert(s.vio != nullptr);
69   }
70 
71   if (!TSVIOBufferGet(vio)) {
72     TSVIONBytesSet(s.vio, TSVIONDoneGet(vio));
73     TSVIOReenable(s.vio);
74     return;
75   }
76 
77   int64_t toWrite = TSVIONTodoGet(vio);
78   assert(toWrite >= 0);
79 
80   if (toWrite > 0) {
81     toWrite = std::min(toWrite, TSIOBufferReaderAvail(TSVIOReaderGet(vio)));
82     assert(toWrite >= 0);
83 
84     if (toWrite > 0) {
85       TSIOBufferCopy(TSVIOBufferGet(s.vio), TSVIOReaderGet(vio), toWrite, 0);
86       TSIOBufferReaderConsume(TSVIOReaderGet(vio), toWrite);
87       TSVIONDoneSet(vio, TSVIONDoneGet(vio) + toWrite);
88     }
89   }
90 
91   if (TSVIONTodoGet(vio) > 0) {
92     if (toWrite > 0) {
93       TSVIOReenable(s.vio);
94       TSContCall(TSVIOContGet(vio), TS_EVENT_VCONN_WRITE_READY, vio);
95     }
96   } else {
97     TSVIONBytesSet(s.vio, TSVIONDoneGet(vio));
98     TSVIOReenable(s.vio);
99     TSContCall(TSVIOContGet(vio), TS_EVENT_VCONN_WRITE_COMPLETE, vio);
100   }
101 }
102 
103 int
handlePost(TSCont c,TSEvent e,void * data)104 handlePost(TSCont c, TSEvent e, void *data)
105 {
106   assert(c != nullptr);
107   // TODO(dmorilha): assert on possible events.
108   PostState *const state = static_cast<PostState *>(TSContDataGet(c));
109   assert(state != nullptr);
110   if (TSVConnClosedGet(c)) {
111     assert(data != nullptr);
112     if (state->reader != nullptr) {
113       addBody(state->requests, state->reader);
114     }
115     dispatch(state->requests, timeout);
116     delete state;
117     TSContDataSet(c, nullptr);
118     TSContDestroy(c);
119     return 0;
120   } else {
121     switch (e) {
122     case TS_EVENT_ERROR: {
123       const TSVIO vio = TSVConnWriteVIOGet(c);
124       assert(vio != nullptr);
125       TSContCall(TSVIOContGet(vio), TS_EVENT_ERROR, vio);
126     } break;
127     case TS_EVENT_VCONN_WRITE_COMPLETE:
128       TSVConnShutdown(TSTransformOutputVConnGet(c), 0, 1);
129       break;
130 
131     case TS_EVENT_VCONN_WRITE_READY:
132     default:
133       postTransform(c, *state);
134       break;
135     }
136   }
137   return 0;
138 }
139