]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ICAP/ICAPOptXact.cc
- ICAP-unrelated improvements from the squid3-icap branch on SF
[thirdparty/squid.git] / src / ICAP / ICAPOptXact.cc
1 /*
2 * DEBUG: section 93 ICAP (RFC 3507) Client
3 */
4
5 #include "squid.h"
6 #include "comm.h"
7 #include "HttpReply.h"
8
9 #include "ICAPOptXact.h"
10 #include "ICAPOptions.h"
11 #include "TextException.h"
12
13 CBDATA_CLASS_INIT(ICAPOptXact);
14
15 ICAPOptXact::ICAPOptXact(ICAPServiceRep::Pointer &aService, Callback *aCbAddr, void *aCbData):
16 ICAPXaction("ICAPOptXact"),
17 cbAddr(aCbAddr), cbData(cbdataReference(aCbData))
18 {
19 Must(aCbAddr && aCbData);
20 service(aService);
21 }
22
23 ICAPOptXact::~ICAPOptXact()
24 {
25 if (cbAddr) {
26 debugs(93, 1, HERE << "BUG: exiting without sending options");
27 cbdataReferenceDone(cbData);
28 }
29 }
30
31 void ICAPOptXact::start()
32 {
33 ICAPXaction_Enter(start);
34
35 ICAPXaction::start();
36
37 Must(self != NULL); // set by AsyncStart;
38
39 openConnection();
40
41 ICAPXaction_Exit();
42 }
43
44 void ICAPOptXact::handleCommConnected()
45 {
46 scheduleRead();
47
48 MemBuf requestBuf;
49 requestBuf.init();
50 makeRequest(requestBuf);
51 debugs(93, 9, "ICAPOptXact request " << status() << ":\n" <<
52 (requestBuf.terminate(), requestBuf.content()));
53
54 scheduleWrite(requestBuf);
55 }
56
57 void ICAPOptXact::makeRequest(MemBuf &buf)
58 {
59 const ICAPServiceRep &s = service();
60 buf.Printf("OPTIONS %s ICAP/1.0\r\n", s.uri.buf());
61 buf.Printf("Host: %s:%d\r\n", s.host.buf(), s.port);
62 buf.append(ICAP::crlf, 2);
63 }
64
65 void ICAPOptXact::handleCommWrote(size_t size)
66 {
67 debugs(93, 9, "ICAPOptXact finished writing " << size <<
68 "-byte request " << status());
69 }
70
71 // comm module read a portion of the ICAP response for us
72 void ICAPOptXact::handleCommRead(size_t)
73 {
74 if (ICAPOptions *options = parseResponse()) {
75 sendOptions(options);
76 Must(done()); // there should be nothing else to do
77 return;
78 }
79
80 scheduleRead();
81 }
82
83 ICAPOptions *ICAPOptXact::parseResponse()
84 {
85 debugs(93, 5, HERE << "have " << readBuf.contentSize() << " bytes to parse" <<
86 status());
87 debugs(93, 5, HERE << "\n" << readBuf.content());
88
89 HttpReply *r = new HttpReply;
90 r->protoPrefix = "ICAP/"; // TODO: make an IcapReply class?
91
92 if (!parseHttpMsg(r)) { // throws on errors
93 delete r;
94 return 0;
95 }
96
97 if (httpHeaderHasConnDir(&r->header, "close"))
98 reuseConnection = false;
99
100 ICAPOptions *options = new ICAPOptions;
101 options->configure(r);
102
103 delete r;
104
105 return options;
106 }
107
108 void ICAPOptXact::swanSong() {
109 if (cbAddr) {
110 debugs(93, 3, HERE << "probably failed; sending NULL options");
111 sendOptions(0);
112 }
113 ICAPXaction::swanSong();
114 }
115
116 void ICAPOptXact::sendOptions(ICAPOptions *options) {
117 debugs(93, 3, HERE << "sending options " << options << " to " << cbData <<
118 " at " << (void*)cbAddr << status());
119
120 Must(cbAddr);
121 Callback *addr = cbAddr;
122 cbAddr = NULL; // in case the callback calls us or throws
123
124 void *data = NULL;
125 if (cbdataReferenceValidDone(cbData, &data))
126 (*addr)(options, data); // callee takes ownership of the options
127 else
128 debugs(93, 2, HERE << "sending options " << options << " to " <<
129 data << " failed" << status());
130 }