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