]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/icap/OptXact.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / adaptation / icap / OptXact.cc
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 93 ICAP (RFC 3507) Client */
10
11 #include "squid.h"
12 #include "adaptation/Answer.h"
13 #include "adaptation/icap/Config.h"
14 #include "adaptation/icap/Options.h"
15 #include "adaptation/icap/OptXact.h"
16 #include "base/TextException.h"
17 #include "comm.h"
18 #include "HttpHeaderTools.h"
19 #include "HttpReply.h"
20 #include "HttpRequest.h"
21 #include "SquidTime.h"
22
23 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, OptXact);
24 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, OptXactLauncher);
25
26 Adaptation::Icap::OptXact::OptXact(Adaptation::Icap::ServiceRep::Pointer &aService):
27 AsyncJob("Adaptation::Icap::OptXact"),
28 Adaptation::Icap::Xaction("Adaptation::Icap::OptXact", aService),
29 readAll(false)
30 {
31 }
32
33 void Adaptation::Icap::OptXact::start()
34 {
35 Adaptation::Icap::Xaction::start();
36
37 openConnection();
38 }
39
40 void Adaptation::Icap::OptXact::handleCommConnected()
41 {
42 scheduleRead();
43
44 MemBuf requestBuf;
45 requestBuf.init();
46 makeRequest(requestBuf);
47 debugs(93, 9, HERE << "request " << status() << ":\n" <<
48 (requestBuf.terminate(), requestBuf.content()));
49 icap_tio_start = current_time;
50 scheduleWrite(requestBuf);
51 }
52
53 void Adaptation::Icap::OptXact::makeRequest(MemBuf &buf)
54 {
55 const Adaptation::Service &s = service();
56 const String uri = s.cfg().uri;
57 buf.appendf("OPTIONS " SQUIDSTRINGPH " ICAP/1.0\r\n", SQUIDSTRINGPRINT(uri));
58 const String host = s.cfg().host;
59 buf.appendf("Host: " SQUIDSTRINGPH ":%d\r\n", SQUIDSTRINGPRINT(host), s.cfg().port);
60
61 if (!TheConfig.reuse_connections)
62 buf.append("Connection: close\r\n", 19);
63
64 buf.append("Allow: ", 7);
65 if (TheConfig.allow206_enable)
66 buf.append("206, ", 5);
67 buf.append("trailers\r\n", 10);
68 buf.append(ICAP::crlf, 2);
69
70 // XXX: HttpRequest cannot fully parse ICAP Request-Line
71 Http::StatusCode reqStatus;
72 buf.terminate(); // Http::Message::parse requires terminated buffer
73 Must(icapRequest->parse(buf.content(), buf.contentSize(), true, &reqStatus) > 0);
74 }
75
76 void Adaptation::Icap::OptXact::handleCommWrote(size_t size)
77 {
78 debugs(93, 9, HERE << "finished writing " << size <<
79 "-byte request " << status());
80 }
81
82 // comm module read a portion of the ICAP response for us
83 void Adaptation::Icap::OptXact::handleCommRead(size_t)
84 {
85 if (parseResponse()) {
86 Must(icapReply != NULL);
87 // We read everything if there is no response body. If there is a body,
88 // we cannot parse it because we do not support any opt-body-types, so
89 // we leave readAll false which forces connection closure.
90 readAll = icapReply->header.getByNameListMember("Encapsulated",
91 "opt-body", ',').isEmpty();
92 debugs(93, 7, HERE << "readAll=" << readAll);
93 icap_tio_finish = current_time;
94 setOutcome(xoOpt);
95 sendAnswer(Answer::Forward(icapReply.getRaw()));
96 Must(done()); // there should be nothing else to do
97 return;
98 }
99
100 scheduleRead();
101 }
102
103 bool Adaptation::Icap::OptXact::parseResponse()
104 {
105 debugs(93, 5, "have " << readBuf.length() << " bytes to parse" << status());
106 debugs(93, DBG_DATA, "\n" << readBuf);
107
108 HttpReply::Pointer r(new HttpReply);
109 r->protoPrefix = "ICAP/"; // TODO: make an IcapReply class?
110
111 if (!parseHttpMsg(r.getRaw())) // throws on errors
112 return false;
113
114 static SBuf close("close", 5);
115 if (httpHeaderHasConnDir(&r->header, close))
116 reuseConnection = false;
117
118 icapReply = r;
119 return true;
120 }
121
122 void Adaptation::Icap::OptXact::swanSong()
123 {
124 Adaptation::Icap::Xaction::swanSong();
125 }
126
127 void Adaptation::Icap::OptXact::finalizeLogInfo()
128 {
129 // al.cache.caddr = 0;
130 al.icap.reqMethod = Adaptation::methodOptions;
131
132 if (icapReply != NULL && al.icap.bytesRead > icapReply->hdr_sz)
133 al.icap.bodyBytesRead = al.icap.bytesRead - icapReply->hdr_sz;
134
135 Adaptation::Icap::Xaction::finalizeLogInfo();
136 }
137
138 /* Adaptation::Icap::OptXactLauncher */
139
140 Adaptation::Icap::OptXactLauncher::OptXactLauncher(Adaptation::ServicePointer aService):
141 AsyncJob("Adaptation::Icap::OptXactLauncher"),
142 Adaptation::Icap::Launcher("Adaptation::Icap::OptXactLauncher", aService)
143 {
144 }
145
146 Adaptation::Icap::Xaction *Adaptation::Icap::OptXactLauncher::createXaction()
147 {
148 Adaptation::Icap::ServiceRep::Pointer s =
149 dynamic_cast<Adaptation::Icap::ServiceRep*>(theService.getRaw());
150 Must(s != NULL);
151 return new Adaptation::Icap::OptXact(s);
152 }
153