1 package it.com.atlassian.plugins.rest.sample.entities;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.io.OutputStream;
8 import java.net.ServerSocket;
9 import java.net.Socket;
10 import java.net.URI;
11 import java.util.concurrent.atomic.AtomicBoolean;
12
13 import com.atlassian.plugins.rest.sample.entities.UriBuilder;
14
15 import org.apache.commons.httpclient.HttpClient;
16 import org.apache.commons.httpclient.HttpStatus;
17 import org.apache.commons.httpclient.methods.PostMethod;
18 import org.apache.commons.httpclient.methods.RequestEntity;
19 import org.apache.commons.httpclient.methods.StringRequestEntity;
20 import org.junit.After;
21 import org.junit.Before;
22 import org.junit.Test;
23
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26
27 public class DtdReadingTest {
28 public static final String FRUIT_RESOURCE = "fruit";
29 private static final String BASKET_RESOURCE = "fruit-basket";
30 HttpAttemptDetector detector;
31 Thread t;
32
33 @Before
34 public void setupDetector() throws IOException {
35 detector = new HttpAttemptDetector();
36 t = new Thread(detector);
37 t.start();
38 }
39
40 @After
41 public void stopListenerThread() throws IOException {
42 detector.shutdown();
43 }
44
45 PostMethod postResource(String resource, String content) throws IOException {
46 RequestEntity re = new StringRequestEntity(content, "application/xml", "us-ascii");
47
48 final URI baseUri = UriBuilder.create().path("rest").path("entity").path("latest").path(resource).build();
49
50 HttpClient client = new HttpClient();
51
52 PostMethod m = new PostMethod(baseUri.toString());
53
54 m.setRequestHeader("Accept", "application/xml");
55 m.setRequestEntity(re);
56
57 client.executeMethod(m);
58
59 return m;
60 }
61
62 @Test
63 public void externalDtdIsNotRead() throws Exception {
64 String content = "<!DOCTYPE x SYSTEM '" + detector.getUrl() + "'><orange><name>test</name></orange>";
65 PostMethod m = postResource(FRUIT_RESOURCE, content);
66 assertEquals(HttpStatus.SC_OK, m.getStatusCode());
67 assertFalse("An HTTP request should not be attempted", detector.wasAttempted());
68 }
69
70 @Test
71 public void externalDtdIsNotReadWhenListParameter() throws Exception {
72 String content = "<!DOCTYPE x SYSTEM '" + detector.getUrl() + "'><basket><orange><name>orange-one</name></orange><orange><name>orange-two</name></orange></basket>";
73 PostMethod m = postResource(BASKET_RESOURCE, content);
74 assertEquals(HttpStatus.SC_OK, m.getStatusCode());
75 assertFalse("An HTTP request should not be attempted", detector.wasAttempted());
76 }
77
78 @Test
79 public void externalGeneralEntityIsNotRead() throws Exception {
80 String content = "<!DOCTYPE x [<!ENTITY e SYSTEM '" + detector.getUrl() + "'>]><orange><name>&e;</name></orange>";
81 PostMethod m = postResource(FRUIT_RESOURCE, content);
82 assertEquals(HttpStatus.SC_OK, m.getStatusCode());
83 assertFalse("An HTTP request should not be attempted", detector.wasAttempted());
84 }
85
86 @Test
87 public void externalGeneralEntityIsNotReadWhenListParameter() throws Exception {
88 String content = "<!DOCTYPE x [<!ENTITY e SYSTEM '" + detector.getUrl() + "'>]><basket><orange><name>&e;</name></orange></basket>";
89 PostMethod m = postResource(BASKET_RESOURCE, content);
90 assertEquals(HttpStatus.SC_BAD_REQUEST, m.getStatusCode());
91 assertFalse("An HTTP request should not be attempted", detector.wasAttempted());
92 }
93
94 @Test
95 public void externalParameterEntityIsNotRead() throws Exception {
96 String content = "<!DOCTYPE x [<!ENTITY % pe SYSTEM '" + detector.getUrl() + "'> %pe;]><orange><name>test</name></orange>";
97 PostMethod m = postResource(FRUIT_RESOURCE, content);
98 assertEquals(HttpStatus.SC_OK, m.getStatusCode());
99 assertFalse("An HTTP request should not be attempted", detector.wasAttempted());
100 }
101
102 @Test
103 public void externalParameterEntityIsNotReadWhenListParameter() throws Exception {
104 String content = "<!DOCTYPE x [<!ENTITY % pe SYSTEM '" + detector.getUrl() + "'> %pe;]><basket><orange><name>test</name></orange></basket>";
105 PostMethod m = postResource(BASKET_RESOURCE, content);
106 assertEquals(HttpStatus.SC_OK, m.getStatusCode());
107 assertFalse("An HTTP request should not be attempted", detector.wasAttempted());
108 }
109
110
111
112
113 static class HttpAttemptDetector implements Runnable {
114 private final ServerSocket serverSocket;
115 private final AtomicBoolean someoneConnected = new AtomicBoolean(false);
116
117 public HttpAttemptDetector() throws IOException {
118 serverSocket = new ServerSocket(0);
119 }
120
121 public String getUrl() {
122 return "http://localhost:" + serverSocket.getLocalPort();
123 }
124
125 public void run() {
126 while (true) {
127 try {
128 Socket s = serverSocket.accept();
129 someoneConnected.set(true);
130
131
132 final InputStream in = s.getInputStream();
133 final BufferedReader br = new BufferedReader(new InputStreamReader(in, "us-ascii"));
134
135 String str;
136
137 while ((str = br.readLine()) != null && !str.isEmpty()) ;
138
139 OutputStream out = s.getOutputStream();
140 out.write("HTTP/1.0 200 OK\r\n\r\n".getBytes("us-ascii"));
141 out.close();
142 s.close();
143 } catch (IOException e) {
144 }
145 }
146 }
147
148 void shutdown() throws IOException {
149 serverSocket.close();
150 }
151
152 public boolean wasAttempted() {
153 return someoneConnected.get();
154 }
155 }
156 }