View Javadoc

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());  // entity is not defined because DTD is not read
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      * Listen on a socket, flag connection attempts.
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                     /* Pretend to be an HTTP server serving up an empty stream of bytes */
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 }