1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package org.apache.commons.httpclient.methods;
33
34 import java.io.IOException;
35 import org.apache.commons.httpclient.HttpConnection;
36 import org.apache.commons.httpclient.HttpException;
37 import org.apache.commons.httpclient.HttpState;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 /***
42 * <p>
43 * This abstract class serves as a foundation for all HTTP methods
44 * that support 'Expect: 100-continue' handshake.
45 * </p>
46 *
47 * <p>
48 * The purpose of the 100 (Continue) status (refer to section 10.1.1
49 * of the RFC 2616 for more details) is to allow a client that is
50 * sending a request message with a request body to determine if the
51 * origin server is willing to accept the request (based on the request
52 * headers) before the client sends the request body. In some cases,
53 * it might either be inappropriate or highly inefficient for the
54 * client to send the body if the server will reject the message
55 * without looking at the body.
56 * </p>
57 *
58 * <p>
59 * 'Expect: 100-continue' handshake should be used with caution,
60 * as it may cause problems with HTTP servers and proxies that
61 * do not support HTTP/1.1 protocol.
62 * </p>
63 *
64 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
65 *
66 * @since 2.0beta1
67 */
68
69 public abstract class ExpectContinueMethod extends GetMethod {
70
71 /*** This flag specifies whether "expect: 100-continue" handshake is
72 * to be used prior to sending the request body */
73 private boolean useExpectHeader = false;
74
75 /*** LOG object for this class. */
76 private static final Log LOG = LogFactory.getLog(ExpectContinueMethod.class);
77
78 /***
79 * No-arg constructor.
80 *
81 * @since 2.0
82 */
83 public ExpectContinueMethod() {
84 super();
85 }
86
87 /***
88 * Constructor specifying a URI.
89 *
90 * @param uri either an absolute or relative URI
91 *
92 * @since 2.0
93 */
94 public ExpectContinueMethod(String uri) {
95 super(uri);
96 }
97
98 /***
99 * Constructor specifying a URI and a tempDir.
100 *
101 * @param uri either an absolute or relative URI
102 * @param tempDir directory to store temp files in
103 *
104 * @deprecated the client is responsible for disk I/O
105 * @since 2.0
106 */
107 public ExpectContinueMethod(String uri, String tempDir) {
108 super(uri, tempDir);
109 }
110
111 /***
112 * Constructor specifying a URI, tempDir and tempFile.
113 *
114 * @param uri either an absolute or relative URI
115 * @param tempDir directory to store temp files in
116 * @param tempFile file to store temporary data in
117 *
118 * @deprecated the client is responsible for disk I/O
119 * @since 2.0
120 */
121 public ExpectContinueMethod(String uri, String tempDir, String tempFile) {
122 super(uri, tempDir, tempFile);
123 }
124
125 /***
126 * <p>
127 * Returns <tt>true</tt> if the 'Expect: 100-Continue' handshake
128 * is activated. The purpose of the 'Expect: 100-Continue'
129 * handshake to allow a client that is sending a request message
130 * with a request body to determine if the origin server is
131 * willing to accept the request (based on the request headers)
132 * before the client sends the request body.
133 * </p>
134 *
135 * @return <tt>true</tt> if 'Expect: 100-Continue' handshake is to
136 * be used, <tt>false</tt> otherwise.
137 *
138 * @since 2.0beta1
139 */
140 public boolean getUseExpectHeader() {
141 return this.useExpectHeader;
142 }
143
144 /***
145 * <p>
146 * Activates 'Expect: 100-Continue' handshake. The purpose of
147 * the 'Expect: 100-Continue' handshake to allow a client that is
148 * sending a request message with a request body to determine if
149 * the origin server is willing to accept the request (based on
150 * the request headers) before the client sends the request body.
151 * </p>
152 *
153 * <p>
154 * The use of the 'Expect: 100-continue' handshake can result in
155 * noticable peformance improvement for entity enclosing requests
156 * (such as POST and PUT) that require the target server's
157 * authentication.
158 * </p>
159 *
160 * <p>
161 * 'Expect: 100-continue' handshake should be used with
162 * caution, as it may cause problems with HTTP servers and
163 * proxies that do not support HTTP/1.1 protocol.
164 * </p>
165 *
166 * @param value boolean value
167 *
168 *
169 * @since 2.0beta1
170 */
171 public void setUseExpectHeader(boolean value) {
172 this.useExpectHeader = value;
173 }
174
175 /***
176 * Returns <tt>true</tt> if there is a request body to be sent.
177 * 'Expect: 100-continue' handshake may not be used if request
178 * body is not present
179 *
180 * @return boolean
181 *
182 * @since 2.0beta1
183 */
184 protected abstract boolean hasRequestContent();
185
186 /***
187 * Sets the <tt>Expect</tt> header if it has not already been set,
188 * in addition to the "standard" set of headers.
189 *
190 * @param state the {@link HttpState state} information associated with this method
191 * @param conn the {@link HttpConnection connection} used to execute
192 * this HTTP method
193 *
194 * @throws IOException if an I/O (transport) error occurs
195 * @throws HttpException if a protocol exception occurs.
196 * @throws HttpRecoverableException if a recoverable transport error occurs.
197 * Usually this kind of exceptions can be recovered from by
198 * retrying the HTTP method
199 */
200 protected void addRequestHeaders(HttpState state, HttpConnection conn)
201 throws IOException, HttpException {
202 LOG.trace("enter ExpectContinueMethod.addRequestHeaders(HttpState, HttpConnection)");
203
204 super.addRequestHeaders(state, conn);
205
206 boolean headerPresent = (getRequestHeader("Expect") != null);
207
208
209
210
211 if (getUseExpectHeader() && isHttp11() && hasRequestContent()) {
212 if (!headerPresent) {
213 setRequestHeader("Expect", "100-continue");
214 }
215 } else {
216 if (headerPresent) {
217 removeRequestHeader("Expect");
218 }
219 }
220 }
221 }