View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  
16  package org.fourthline.cling.test.control;
17  
18  import org.fourthline.cling.mock.MockUpnpService;
19  import org.fourthline.cling.mock.MockUpnpServiceConfiguration;
20  import org.fourthline.cling.model.action.ActionException;
21  import org.fourthline.cling.model.action.ActionInvocation;
22  import org.fourthline.cling.model.message.StreamRequestMessage;
23  import org.fourthline.cling.model.message.StreamResponseMessage;
24  import org.fourthline.cling.model.message.UpnpMessage;
25  import org.fourthline.cling.model.message.UpnpRequest;
26  import org.fourthline.cling.model.message.UpnpResponse;
27  import org.fourthline.cling.model.message.control.IncomingActionRequestMessage;
28  import org.fourthline.cling.model.message.control.IncomingActionResponseMessage;
29  import org.fourthline.cling.model.message.control.OutgoingActionRequestMessage;
30  import org.fourthline.cling.model.message.control.OutgoingActionResponseMessage;
31  import org.fourthline.cling.model.message.header.ContentTypeHeader;
32  import org.fourthline.cling.model.message.header.SoapActionHeader;
33  import org.fourthline.cling.model.message.header.UpnpHeader;
34  import org.fourthline.cling.model.meta.Action;
35  import org.fourthline.cling.model.meta.LocalDevice;
36  import org.fourthline.cling.model.meta.LocalService;
37  import org.fourthline.cling.model.types.ErrorCode;
38  import org.fourthline.cling.model.types.SoapActionType;
39  import org.fourthline.cling.test.data.SampleData;
40  import org.fourthline.cling.transport.impl.PullSOAPActionProcessorImpl;
41  import org.fourthline.cling.transport.impl.RecoveringSOAPActionProcessorImpl;
42  import org.fourthline.cling.transport.impl.SOAPActionProcessorImpl;
43  import org.fourthline.cling.transport.spi.SOAPActionProcessor;
44  import org.testng.annotations.DataProvider;
45  import org.testng.annotations.Test;
46  
47  import java.net.URI;
48  
49  import static org.testng.Assert.*;
50  
51  public class ActionXMLProcessingTest {
52  
53      public static final String ENCODED_REQUEST = "<?xml version=\"1.0\"?>\n" +
54              " <s:Envelope\n" +
55              "     xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
56              "     s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
57              "   <s:Body>\n" +
58              "     <u:SetSomeValue xmlns:u=\"urn:schemas-upnp-org:service:SwitchPower:1\">\n" +
59              "       <SomeValue>This is encoded: &lt;</SomeValue>\n" +
60              "     </u:SetSomeValue>\n" +
61              "   </s:Body>\n" +
62              " </s:Envelope>";
63  
64      public static final String ALIAS_ENCODED_REQUEST = "<?xml version=\"1.0\"?>\n" +
65              " <s:Envelope\n" +
66              "     xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
67              "     s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
68              "   <s:Body>\n" +
69              "     <u:SetSomeValue xmlns:u=\"urn:schemas-upnp-org:service:SwitchPower:1\">\n" +
70              "       <SomeValue1>This is encoded: &lt;</SomeValue1>\n" +
71              "     </u:SetSomeValue>\n" +
72              "   </s:Body>\n" +
73              " </s:Envelope>";
74  
75      @DataProvider(name = "processors")
76      public SOAPActionProcessor[][] getProcessors() {
77          return new SOAPActionProcessor[][] {
78              {new SOAPActionProcessorImpl()},
79              {new PullSOAPActionProcessorImpl()},
80              {new RecoveringSOAPActionProcessorImpl()}
81          };
82      }
83  
84      @Test(dataProvider = "processors")
85      public void writeReadRequest(final SOAPActionProcessor processor) throws Exception {
86  
87          LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceExtended.class);
88          LocalService svc = ld.getServices()[0];
89  
90          Action action = svc.getAction("SetTarget");
91          ActionInvocation actionInvocation = new ActionInvocation(action);
92          actionInvocation.setInput("NewTargetValue", true);
93  
94          // The control URL doesn't matter
95          OutgoingActionRequestMessage outgoingCall = new OutgoingActionRequestMessage(actionInvocation, SampleData.getLocalBaseURL());
96  
97          MockUpnpService upnpService = new MockUpnpService(new MockUpnpServiceConfiguration() {
98              @Override
99              public SOAPActionProcessor getSoapActionProcessor() {
100                 return processor;
101             }
102         });
103 
104         upnpService.getConfiguration().getSoapActionProcessor().writeBody(outgoingCall, actionInvocation);
105 
106         StreamRequestMessage incomingStream = new StreamRequestMessage(outgoingCall);
107         IncomingActionRequestMessage incomingCall = new IncomingActionRequestMessage(incomingStream, svc);
108 
109         actionInvocation = new ActionInvocation(incomingCall.getAction());
110 
111         upnpService.getConfiguration().getSoapActionProcessor().readBody(incomingCall, actionInvocation);
112 
113         assertEquals(actionInvocation.getInput().length, 1);
114         assertEquals(actionInvocation.getInput()[0].getArgument().getName(), "NewTargetValue");
115     }
116 
117     @Test(dataProvider = "processors")
118     public void writeReadResponse(final SOAPActionProcessor processor) throws Exception {
119 
120         LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceExtended.class);
121         LocalService svc = ld.getServices()[0];
122 
123         Action action = svc.getAction("GetTarget");
124         ActionInvocation actionInvocation = new ActionInvocation(action);
125 
126         OutgoingActionResponseMessage outgoingCall = new OutgoingActionResponseMessage(action);
127         actionInvocation.setOutput("RetTargetValue", true);
128 
129         MockUpnpService upnpService = new MockUpnpService(new MockUpnpServiceConfiguration() {
130             @Override
131             public SOAPActionProcessor getSoapActionProcessor() {
132                 return processor;
133             }
134         });
135 
136         upnpService.getConfiguration().getSoapActionProcessor().writeBody(outgoingCall, actionInvocation);
137 
138         StreamResponseMessage incomingStream = new StreamResponseMessage(outgoingCall);
139         IncomingActionResponseMessage incomingCall = new IncomingActionResponseMessage(incomingStream);
140 
141         actionInvocation = new ActionInvocation(action);
142         upnpService.getConfiguration().getSoapActionProcessor().readBody(incomingCall, actionInvocation);
143 
144         assertEquals(actionInvocation.getOutput()[0].getArgument().getName(), "RetTargetValue");
145     }
146 
147     @Test(dataProvider = "processors")
148     public void writeFailureReadFailure(final SOAPActionProcessor processor) throws Exception {
149 
150         LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceExtended.class);
151         LocalService svc = ld.getServices()[0];
152 
153         Action action = svc.getAction("GetTarget");
154         ActionInvocation actionInvocation = new ActionInvocation(action);
155         actionInvocation.setFailure(new ActionException(ErrorCode.ACTION_FAILED, "A test string"));
156 
157         OutgoingActionResponseMessage outgoingCall = new OutgoingActionResponseMessage(UpnpResponse.Status.INTERNAL_SERVER_ERROR);
158 
159         MockUpnpService upnpService = new MockUpnpService(new MockUpnpServiceConfiguration() {
160             @Override
161             public SOAPActionProcessor getSoapActionProcessor() {
162                 return processor;
163             }
164         });
165 
166         upnpService.getConfiguration().getSoapActionProcessor().writeBody(outgoingCall, actionInvocation);
167 
168         StreamResponseMessage incomingStream = new StreamResponseMessage(outgoingCall);
169         IncomingActionResponseMessage incomingCall = new IncomingActionResponseMessage(incomingStream);
170 
171         actionInvocation = new ActionInvocation(action);
172         upnpService.getConfiguration().getSoapActionProcessor().readBody(incomingCall, actionInvocation);
173 
174         assertEquals(actionInvocation.getFailure().getErrorCode(), ErrorCode.ACTION_FAILED.getCode());
175         // Note the period at the end of the test string!
176         assertEquals(actionInvocation.getFailure().getMessage(), ErrorCode.ACTION_FAILED.getDescription() + ". A test string.");
177     }
178 
179     @Test(dataProvider = "processors")
180     public void readEncodedRequest(final SOAPActionProcessor processor) throws Exception {
181 
182         LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceExtended.class);
183         LocalService svc = ld.getServices()[0];
184 
185         Action action = svc.getAction("SetSomeValue");
186         ActionInvocation actionInvocation = new ActionInvocation(action);
187 
188         MockUpnpService upnpService = new MockUpnpService(new MockUpnpServiceConfiguration() {
189             @Override
190             public SOAPActionProcessor getSoapActionProcessor() {
191                 return processor;
192             }
193         });
194 
195         StreamRequestMessage streamRequest = new StreamRequestMessage(UpnpRequest.Method.POST, URI.create("http://some.uri"));
196         streamRequest.getHeaders().add(
197                 UpnpHeader.Type.CONTENT_TYPE,
198                 new ContentTypeHeader(ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8)
199         );
200         streamRequest.getHeaders().add(
201                 UpnpHeader.Type.SOAPACTION,
202                 new SoapActionHeader(
203                         new SoapActionType(
204                                 action.getService().getServiceType(),
205                                 action.getName()
206                         )
207                 )
208         );
209         streamRequest.setBody(UpnpMessage.BodyType.STRING, ENCODED_REQUEST);
210 
211         IncomingActionRequestMessage request = new IncomingActionRequestMessage(streamRequest, svc);
212 
213         upnpService.getConfiguration().getSoapActionProcessor().readBody(request, actionInvocation);
214 
215         assertEquals(actionInvocation.getInput()[0].toString(), "This is encoded: <");
216 
217     }
218 
219     @Test(dataProvider = "processors")
220     public void readEncodedRequestWithAlias(final SOAPActionProcessor processor) throws Exception {
221 
222         LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceExtended.class);
223         LocalService svc = ld.getServices()[0];
224 
225         Action action = svc.getAction("SetSomeValue");
226         ActionInvocation actionInvocation = new ActionInvocation(action);
227 
228         MockUpnpService upnpService = new MockUpnpService(new MockUpnpServiceConfiguration() {
229             @Override
230             public SOAPActionProcessor getSoapActionProcessor() {
231                 return processor;
232             }
233         });
234 
235         StreamRequestMessage streamRequest = new StreamRequestMessage(UpnpRequest.Method.POST, URI.create("http://some.uri"));
236         streamRequest.getHeaders().add(
237                 UpnpHeader.Type.CONTENT_TYPE,
238                 new ContentTypeHeader(ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8)
239         );
240         streamRequest.getHeaders().add(
241                 UpnpHeader.Type.SOAPACTION,
242                 new SoapActionHeader(
243                         new SoapActionType(
244                                 action.getService().getServiceType(),
245                                 action.getName()
246                         )
247                 )
248         );
249         streamRequest.setBody(UpnpMessage.BodyType.STRING, ALIAS_ENCODED_REQUEST);
250 
251         IncomingActionRequestMessage request = new IncomingActionRequestMessage(streamRequest, svc);
252 
253         upnpService.getConfiguration().getSoapActionProcessor().readBody(request, actionInvocation);
254 
255         assertEquals(actionInvocation.getInput()[0].toString(), "This is encoded: <");
256         assertEquals(actionInvocation.getInput("SomeValue").toString(), "This is encoded: <");
257 
258     }
259 
260     @Test(dataProvider = "processors")
261     public void writeDecodedResponse(final SOAPActionProcessor processor) throws Exception {
262 
263         LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceExtended.class);
264         LocalService svc = ld.getServices()[0];
265 
266         Action action = svc.getAction("GetSomeValue");
267         ActionInvocation actionInvocation = new ActionInvocation(action);
268 
269         MockUpnpService upnpService = new MockUpnpService(new MockUpnpServiceConfiguration() {
270             @Override
271             public SOAPActionProcessor getSoapActionProcessor() {
272                 return processor;
273             }
274         });
275 
276         OutgoingActionResponseMessage response = new OutgoingActionResponseMessage(action);
277         actionInvocation.setOutput("SomeValue", "This is decoded: &<>'\"");
278 
279         upnpService.getConfiguration().getSoapActionProcessor().writeBody(response, actionInvocation);
280 
281         // Note that quotes are not encoded because this text is not an XML attribute value!
282         assertTrue(response.getBodyString().contains("<SomeValue>This is decoded: &amp;&lt;&gt;'\"</SomeValue>"));
283     }
284 }