1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package davmail.exchange.dav;
20
21 import davmail.exchange.XMLStreamUtil;
22 import org.apache.commons.httpclient.Header;
23 import org.apache.commons.httpclient.HttpConnection;
24 import org.apache.commons.httpclient.HttpException;
25 import org.apache.commons.httpclient.HttpState;
26 import org.apache.commons.httpclient.HttpStatus;
27 import org.apache.commons.httpclient.methods.PostMethod;
28 import org.apache.commons.httpclient.methods.RequestEntity;
29 import org.apache.jackrabbit.webdav.MultiStatusResponse;
30 import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
31 import org.apache.jackrabbit.webdav.xml.Namespace;
32 import org.apache.log4j.Logger;
33
34 import javax.xml.stream.XMLStreamConstants;
35 import javax.xml.stream.XMLStreamException;
36 import javax.xml.stream.XMLStreamReader;
37 import java.io.FilterInputStream;
38 import java.io.IOException;
39 import java.io.OutputStream;
40 import java.util.ArrayList;
41 import java.util.List;
42
43
44
45
46 public abstract class ExchangeDavMethod extends PostMethod {
47 protected static final Logger LOGGER = Logger.getLogger(ExchangeDavMethod.class);
48 List<MultiStatusResponse> responses;
49
50
51
52
53
54
55 public ExchangeDavMethod(String path) {
56 super(path);
57 setRequestEntity(new RequestEntity() {
58 byte[] content;
59
60 public boolean isRepeatable() {
61 return true;
62 }
63
64 public void writeRequest(OutputStream outputStream) throws IOException {
65 if (content == null) {
66 content = generateRequestContent();
67 }
68 outputStream.write(content);
69 }
70
71 public long getContentLength() {
72 if (content == null) {
73 content = generateRequestContent();
74 }
75 return content.length;
76 }
77
78 public String getContentType() {
79 return "text/xml;charset=UTF-8";
80 }
81 });
82 }
83
84
85
86
87
88
89 protected abstract byte[] generateRequestContent();
90
91 @Override
92 protected void processResponseBody(HttpState httpState, HttpConnection httpConnection) {
93 Header contentTypeHeader = getResponseHeader("Content-Type");
94 if (contentTypeHeader != null && "text/xml".equals(contentTypeHeader.getValue())) {
95 responses = new ArrayList<>();
96 XMLStreamReader reader;
97 try {
98 reader = XMLStreamUtil.createXMLStreamReader(new FilterInputStream(getResponseBodyAsStream()) {
99 final byte[] lastbytes = new byte[3];
100
101 @Override
102 public int read(byte[] bytes, int off, int len) throws IOException {
103 int count = in.read(bytes, off, len);
104
105 for (int i = 0; i < count; i++) {
106 byte currentByte = bytes[off + i];
107 if ((lastbytes[0] == '<') && (currentByte >= '0' && currentByte <= '9')) {
108
109 bytes[off + i] = (byte) (currentByte + 49);
110 }
111 lastbytes[0] = lastbytes[1];
112 lastbytes[1] = lastbytes[2];
113 lastbytes[2] = currentByte;
114 }
115 return count;
116 }
117
118 });
119 while (reader.hasNext()) {
120 reader.next();
121 if (XMLStreamUtil.isStartTag(reader, "response")) {
122 handleResponse(reader);
123 }
124 }
125
126 } catch (IOException | XMLStreamException e) {
127 LOGGER.error("Error while parsing soap response: " + e, e);
128 }
129 }
130 }
131
132 protected void handleResponse(XMLStreamReader reader) throws XMLStreamException {
133 MultiStatusResponse multiStatusResponse = null;
134 String href = null;
135 String responseStatus = "";
136 while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, "response")) {
137 reader.next();
138 if (XMLStreamUtil.isStartTag(reader)) {
139 String tagLocalName = reader.getLocalName();
140 if ("href".equals(tagLocalName)) {
141 href = reader.getElementText();
142 } else if ("status".equals(tagLocalName)) {
143 responseStatus = reader.getElementText();
144 } else if ("propstat".equals(tagLocalName)) {
145 if (multiStatusResponse == null) {
146 multiStatusResponse = new MultiStatusResponse(href, responseStatus);
147 }
148 handlePropstat(reader, multiStatusResponse);
149 }
150 }
151 }
152 if (multiStatusResponse != null) {
153 responses.add(multiStatusResponse);
154 }
155 }
156
157 protected void handlePropstat(XMLStreamReader reader, MultiStatusResponse multiStatusResponse) throws XMLStreamException {
158 int propstatStatus = 0;
159 while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, "propstat")) {
160 reader.next();
161 if (XMLStreamUtil.isStartTag(reader)) {
162 String tagLocalName = reader.getLocalName();
163 if ("status".equals(tagLocalName)) {
164 if ("HTTP/1.1 200 OK".equals(reader.getElementText())) {
165 propstatStatus = HttpStatus.SC_OK;
166 } else {
167 propstatStatus = 0;
168 }
169 } else if ("prop".equals(tagLocalName) && propstatStatus == HttpStatus.SC_OK) {
170 handleProperty(reader, multiStatusResponse);
171 }
172 }
173 }
174
175 }
176
177 protected void handleProperty(XMLStreamReader reader, MultiStatusResponse multiStatusResponse) throws XMLStreamException {
178 while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, "prop")) {
179 reader.next();
180 if (XMLStreamUtil.isStartTag(reader)) {
181 Namespace namespace = Namespace.getNamespace(reader.getNamespaceURI());
182 String tagLocalName = reader.getLocalName();
183 if (reader.getAttributeCount() > 0 && "mv.string".equals(reader.getAttributeValue(0))) {
184 handleMultiValuedProperty(reader, multiStatusResponse);
185 } else {
186 String tagContent = getTagContent(reader);
187 if (tagContent != null) {
188 multiStatusResponse.add(new DefaultDavProperty<>(tagLocalName, tagContent, namespace));
189 }
190 }
191 }
192 }
193 }
194
195 protected void handleMultiValuedProperty(XMLStreamReader reader, MultiStatusResponse multiStatusResponse) throws XMLStreamException {
196 String tagLocalName = reader.getLocalName();
197 Namespace namespace = Namespace.getNamespace(reader.getNamespaceURI());
198 ArrayList<String> values = new ArrayList<>();
199 while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, tagLocalName)) {
200 reader.next();
201 if (XMLStreamUtil.isStartTag(reader)) {
202 String tagContent = getTagContent(reader);
203 if (tagContent != null) {
204 values.add(tagContent);
205 }
206 }
207 }
208 multiStatusResponse.add(new DefaultDavProperty<>(tagLocalName, values, namespace));
209 }
210
211 protected String getTagContent(XMLStreamReader reader) throws XMLStreamException {
212 String value = null;
213 String tagLocalName = reader.getLocalName();
214 while (reader.hasNext() &&
215 !((reader.getEventType() == XMLStreamConstants.END_ELEMENT) && tagLocalName.equals(reader.getLocalName()))) {
216 reader.next();
217 if (reader.getEventType() == XMLStreamConstants.CHARACTERS) {
218 value = reader.getText();
219 }
220 }
221
222 if (!reader.hasNext()) {
223 throw new XMLStreamException("End element for " + tagLocalName + " not found");
224 }
225 return value;
226 }
227
228
229
230
231
232
233
234 public MultiStatusResponse[] getResponses() throws HttpException {
235 if (responses == null) {
236 throw new HttpException(getStatusLine().toString());
237 }
238 return responses.toArray(new MultiStatusResponse[0]);
239 }
240
241
242
243
244
245
246
247 public MultiStatusResponse getResponse() throws HttpException {
248 if (responses == null || responses.size() != 1) {
249 throw new HttpException(getStatusLine().toString());
250 }
251 return responses.get(0);
252 }
253
254
255
256
257
258
259
260 public int getResponseStatusCode() throws HttpException {
261 String responseDescription = getResponse().getResponseDescription();
262 if ("HTTP/1.1 201 Created".equals(responseDescription)) {
263 return HttpStatus.SC_CREATED;
264 } else {
265 return HttpStatus.SC_OK;
266 }
267 }
268 }