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 package org.apache.hc.core5.http.protocol;
29
30 import java.io.IOException;
31
32 import org.apache.hc.core5.annotation.Contract;
33 import org.apache.hc.core5.annotation.ThreadingBehavior;
34 import org.apache.hc.core5.http.EntityDetails;
35 import org.apache.hc.core5.http.Header;
36 import org.apache.hc.core5.http.HeaderElements;
37 import org.apache.hc.core5.http.HttpException;
38 import org.apache.hc.core5.http.HttpHeaders;
39 import org.apache.hc.core5.http.HttpRequest;
40 import org.apache.hc.core5.http.HttpRequestInterceptor;
41 import org.apache.hc.core5.http.HttpVersion;
42 import org.apache.hc.core5.http.Method;
43 import org.apache.hc.core5.http.ProtocolException;
44 import org.apache.hc.core5.http.ProtocolVersion;
45 import org.apache.hc.core5.http.message.MessageSupport;
46 import org.apache.hc.core5.util.Args;
47
48
49
50
51
52
53
54
55
56
57
58
59 @Contract(threading = ThreadingBehavior.IMMUTABLE)
60 public class RequestContent implements HttpRequestInterceptor {
61
62
63
64
65
66 public static final HttpRequestInterceptor INSTANCE = new RequestContent();
67
68 private final boolean overwrite;
69
70
71
72
73
74
75 public RequestContent() {
76 this(false);
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90 public RequestContent(final boolean overwrite) {
91 super();
92 this.overwrite = overwrite;
93 }
94
95 @Override
96 public void process(final HttpRequest request, final EntityDetails entity, final HttpContext context)
97 throws HttpException, IOException {
98 Args.notNull(request, "HTTP request");
99 final String method = request.getMethod();
100 if (Method.TRACE.isSame(method) && entity != null) {
101 throw new ProtocolException("TRACE request may not enclose an entity");
102 }
103 if (this.overwrite) {
104 request.removeHeaders(HttpHeaders.TRANSFER_ENCODING);
105 request.removeHeaders(HttpHeaders.CONTENT_LENGTH);
106 } else {
107 if (request.containsHeader(HttpHeaders.TRANSFER_ENCODING)) {
108 throw new ProtocolException("Transfer-encoding header already present");
109 }
110 if (request.containsHeader(HttpHeaders.CONTENT_LENGTH)) {
111 throw new ProtocolException("Content-Length header already present");
112 }
113 }
114 if (entity == null && isContentEnclosingMethod(method)) {
115 request.addHeader(HttpHeaders.CONTENT_LENGTH, "0");
116 return;
117 }
118 if (entity != null) {
119
120
121 validateOptionsContentType(request);
122
123 final ProtocolVersion ver = context.getProtocolVersion();
124
125 if (entity.isChunked() || entity.getContentLength() < 0) {
126 if (ver.lessEquals(HttpVersion.HTTP_1_0)) {
127 throw new ProtocolException(
128 "Chunked transfer encoding not allowed for " + ver);
129 }
130 request.addHeader(HttpHeaders.TRANSFER_ENCODING, HeaderElements.CHUNKED_ENCODING);
131 MessageSupport.addTrailerHeader(request, entity);
132 } else {
133 request.addHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(entity.getContentLength()));
134 }
135 MessageSupport.addContentTypeHeader(request, entity);
136 MessageSupport.addContentEncodingHeader(request, entity);
137 }
138 }
139 private boolean isContentEnclosingMethod(final String method) {
140 return (Method.POST.isSame(method)||Method.PUT.isSame(method)||Method.PATCH.isSame(method));
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 public void validateOptionsContentType(final HttpRequest request) throws ProtocolException {
161 if (Method.OPTIONS.isSame(request.getMethod())) {
162 final Header header = request.getFirstHeader(HttpHeaders.CONTENT_TYPE);
163 if (header == null) {
164 throw new ProtocolException("OPTIONS request must have Content-Type header");
165 }
166 }
167 }
168 }