001package ca.uhn.hl7v2.hoh.encoder;
002
003import static org.junit.Assert.*;
004
005import java.io.ByteArrayInputStream;
006import java.io.ByteArrayOutputStream;
007import java.nio.charset.Charset;
008
009import org.junit.BeforeClass;
010import org.junit.Test;
011
012import ca.uhn.hl7v2.hoh.encoder.AbstractHl7OverHttpDecoder;
013import ca.uhn.hl7v2.hoh.encoder.Hl7OverHttpRequestDecoder;
014import ca.uhn.hl7v2.hoh.util.GZipUtils;
015import ca.uhn.hl7v2.hoh.util.SplitInputStream;
016
017public class Hl7OverHttpDecoderTest {
018
019        private static String ourSampleMessage;
020        private static String ourSampleMessageWithMultibyte;
021
022        @BeforeClass
023        public static void beforeClass() {
024                ourSampleMessage = "MSH|^~\\&|||||200803051508||ADT^A31|2|P|2.5\r" + 
025                                "EVN||200803051509\r" + 
026                                "PID|||ZZZZZZ83M64Z148R^^^SSN^SSN^^20070103\r";
027
028                ourSampleMessageWithMultibyte = ourSampleMessage.replace("SSN", "Iā™„HAPI");
029        }
030
031        // TODO: add test to make sure that a request with chunked encoding can be decoded
032        
033        @Test
034        public void testDecodeFromStream() throws Exception {
035
036                ByteArrayOutputStream bos = new ByteArrayOutputStream();
037                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=ISO-8859-2\r\n" + "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
038                bos.write(msg.getBytes("ISO-8859-1"));
039                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
040                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
041                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
042                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
043
044                assertEquals(0, byteArrayInputStream.available());
045                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
046                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
047                assertTrue(d.isCharsetExplicitlySet());
048                assertEquals("application/hl7-v2", d.getContentType());
049                assertEquals(ourSampleMessage, d.getMessage());
050                assertEquals("hello", d.getUsername());
051                assertEquals("world", d.getPassword());
052                assertEquals("/AppName", d.getPath());
053
054        }
055
056        /**
057         * Allow malformed client to be processed correctly, per
058         * http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.3
059         */
060        @Test
061        public void testDecodeFromStreamWithHeaderLineEndingLF() throws Exception {
062
063                ByteArrayOutputStream bos = new ByteArrayOutputStream();
064                String msg = "POST /AppName HTTP/1.1\n" + // -
065                                "Content-Type: application/hl7-v2; charset=ISO-8859-2\n" + // -
066                                "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\n" + // -
067                                "Authorization: Basic aGVsbG86d29ybGQ=\n" + // -
068                                "\n";
069                bos.write(msg.getBytes("ISO-8859-1"));
070                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
071                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
072                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
073                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
074
075                assertEquals(0, byteArrayInputStream.available());
076                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
077                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
078                assertTrue(d.isCharsetExplicitlySet());
079                assertEquals("application/hl7-v2", d.getContentType());
080                assertEquals(ourSampleMessage, d.getMessage());
081                assertEquals("hello", d.getUsername());
082                assertEquals("world", d.getPassword());
083                assertEquals("/AppName", d.getPath());
084
085        }
086
087        /**
088         * Allow malformed client to be processed correctly, per
089         * http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.3
090         */
091        @Test
092        public void testDecodeFromStreamWithWeirdHeaderLineSpaces() throws Exception {
093
094                ByteArrayOutputStream bos = new ByteArrayOutputStream();
095                String msg = "POST  \t\t /AppName         \tHTTP/1.1\n" + // -
096                                "Content-Type:\t\t application/hl7-v2; charset=ISO-8859-2\n" + // -
097                                "Content-Length:            " + ourSampleMessage.getBytes("ISO-8859-1").length + "\n" + // -
098                                "Authorization:\t\t\t\t Basic aGVsbG86d29ybGQ=\n" + // -
099                                "\n";
100                bos.write(msg.getBytes("ISO-8859-1"));
101                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
102                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
103                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
104                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
105
106                assertEquals(0, byteArrayInputStream.available());
107                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
108                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
109                assertTrue(d.isCharsetExplicitlySet());
110                assertEquals("application/hl7-v2", d.getContentType());
111                assertEquals(ourSampleMessage, d.getMessage());
112                assertEquals("hello", d.getUsername());
113                assertEquals("world", d.getPassword());
114                assertEquals("/AppName", d.getPath());
115
116        }
117
118        @Test
119        public void testDecodeFromStreamWithTwoMessages() throws Exception {
120
121                ByteArrayOutputStream bos = new ByteArrayOutputStream();
122                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=ISO-8859-2\r\n" + "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
123                bos.write(msg.getBytes("ISO-8859-1"));
124                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
125
126                // Double the message
127                bos.write(bos.toByteArray());
128
129                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
130                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
131                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
132
133                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
134                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
135                assertTrue(d.isCharsetExplicitlySet());
136                assertEquals("application/hl7-v2", d.getContentType());
137                assertEquals(ourSampleMessage, d.getMessage());
138                assertEquals("hello", d.getUsername());
139                assertEquals("world", d.getPassword());
140                assertEquals("/AppName", d.getPath());
141
142                // Read a second
143
144                d = new Hl7OverHttpRequestDecoder();
145                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
146
147                assertEquals(0, byteArrayInputStream.available());
148                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
149                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
150                assertTrue(d.isCharsetExplicitlySet());
151                assertEquals("application/hl7-v2", d.getContentType());
152                assertEquals(ourSampleMessage, d.getMessage());
153                assertEquals("hello", d.getUsername());
154                assertEquals("world", d.getPassword());
155                assertEquals("/AppName", d.getPath());
156
157        }
158
159        @Test
160        public void testDecodeFromStreamWithMultibyteSequences() throws Exception {
161                ByteArrayOutputStream bos = new ByteArrayOutputStream();
162                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=UTF-8\r\n" + "Content-Length: " + ourSampleMessageWithMultibyte.getBytes("UTF-8").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
163                bos.write(msg.getBytes("ISO-8859-1"));
164                bos.write(ourSampleMessageWithMultibyte.getBytes("UTF-8"));
165                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
166                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
167                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
168
169                assertEquals(0, byteArrayInputStream.available());
170                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
171                assertEquals(Charset.forName("UTF-8"), d.getCharset());
172                assertTrue(d.isCharsetExplicitlySet());
173                assertEquals("application/hl7-v2", d.getContentType());
174                assertEquals(ourSampleMessageWithMultibyte, d.getMessage());
175                assertEquals("hello", d.getUsername());
176                assertEquals("world", d.getPassword());
177                assertEquals("/AppName", d.getPath());
178
179        }
180
181        @Test
182        public void testDecodeFromStreamWithCompression() throws Exception {
183                byte[] sampleMessage = GZipUtils.compress(ourSampleMessageWithMultibyte.getBytes("UTF-8"));
184
185                ByteArrayOutputStream bos = new ByteArrayOutputStream();
186                String msg = "POST /AppName HTTP/1.1\r\n" + 
187                                "Content-Type: application/hl7-v2; charset=UTF-8\r\n" + 
188                                "Content-Length: " + sampleMessage.length + "\r\n" + 
189                                "Content-Encoding: gzip\r\n" + 
190                                "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
191                
192                bos.write(msg.getBytes("ISO-8859-1"));
193                bos.write(sampleMessage);
194                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
195                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
196                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
197
198                assertEquals(0, byteArrayInputStream.available());
199                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
200                assertEquals(Charset.forName("UTF-8"), d.getCharset());
201                assertTrue(d.isCharsetExplicitlySet());
202                assertEquals("application/hl7-v2", d.getContentType());
203                assertEquals(ourSampleMessageWithMultibyte, d.getMessage());
204                assertEquals("hello", d.getUsername());
205                assertEquals("world", d.getPassword());
206                assertEquals("/AppName", d.getPath());
207
208        }
209
210        @Test
211        public void testDecodeFromStreamWithMultipleMessages() throws Exception {
212
213                ByteArrayOutputStream bos = new ByteArrayOutputStream();
214                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=ISO-8859-2\r\n" + "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
215
216                bos.write(msg.getBytes("ISO-8859-1"));
217                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
218                bos.write(msg.getBytes("ISO-8859-1"));
219                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
220
221                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bos.toByteArray());
222
223                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
224                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
225
226                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
227                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
228                assertTrue(d.isCharsetExplicitlySet());
229                assertEquals("application/hl7-v2", d.getContentType());
230                assertEquals(ourSampleMessage, d.getMessage());
231                assertEquals("hello", d.getUsername());
232                assertEquals("world", d.getPassword());
233                assertEquals("/AppName", d.getPath());
234
235                d = new Hl7OverHttpRequestDecoder();
236                d.readHeadersAndContentsFromInputStreamAndDecode(byteArrayInputStream);
237
238                assertEquals(0, byteArrayInputStream.available());
239                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
240                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
241                assertTrue(d.isCharsetExplicitlySet());
242                assertEquals("application/hl7-v2", d.getContentType());
243                assertEquals(ourSampleMessage, d.getMessage());
244                assertEquals("hello", d.getUsername());
245                assertEquals("world", d.getPassword());
246                assertEquals("/AppName", d.getPath());
247
248        }
249
250        /**
251         * Simulate a network blip causing a delay mid-message
252         */
253        @Test
254        public void testDecodeFromStreamWithPauseInTheMiddleOfMessage() throws Exception {
255
256                ByteArrayOutputStream bos = new ByteArrayOutputStream();
257                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=ISO-8859-2\r\n" + "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
258                bos.write(msg.getBytes("ISO-8859-1"));
259                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
260                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
261
262                ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
263                SplitInputStream is = new SplitInputStream(bais, msg.length() + 10);
264
265                d.readHeadersAndContentsFromInputStreamAndDecode(is);
266
267                assertEquals(0, bais.available());
268                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
269                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
270                assertTrue(d.isCharsetExplicitlySet());
271                assertEquals("application/hl7-v2", d.getContentType());
272                assertEquals(ourSampleMessage, d.getMessage());
273                assertEquals("hello", d.getUsername());
274                assertEquals("world", d.getPassword());
275                assertEquals("/AppName", d.getPath());
276
277        }
278
279        /**
280         * Simulate a network blip causing a delay mid-message
281         */
282        @Test
283        public void testDecodeFromStreamWithPauseInStatusLine() throws Exception {
284
285                ByteArrayOutputStream bos = new ByteArrayOutputStream();
286                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=ISO-8859-2\r\n" + "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
287                bos.write(msg.getBytes("ISO-8859-1"));
288                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
289                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
290
291                ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
292                SplitInputStream is = new SplitInputStream(bais, 5);
293
294                d.readHeadersAndContentsFromInputStreamAndDecode(is);
295
296                assertEquals(0, bais.available());
297                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
298                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
299                assertTrue(d.isCharsetExplicitlySet());
300                assertEquals("application/hl7-v2", d.getContentType());
301                assertEquals(ourSampleMessage, d.getMessage());
302                assertEquals("hello", d.getUsername());
303                assertEquals("world", d.getPassword());
304                assertEquals("/AppName", d.getPath());
305
306        }
307
308        /**
309         * Simulate a network blip causing a delay mid-message
310         */
311        @Test
312        public void testDecodeFromStreamWithPauseInMiddleOfHeaders() throws Exception {
313
314                ByteArrayOutputStream bos = new ByteArrayOutputStream();
315                String msg = "POST /AppName HTTP/1.1\r\n" + "Content-Type: application/hl7-v2; charset=ISO-8859-2\r\n" + "Content-Length: " + ourSampleMessage.getBytes("ISO-8859-1").length + "\r\n" + "Authorization: Basic aGVsbG86d29ybGQ=\r\n" + "\r\n";
316                bos.write(msg.getBytes("ISO-8859-1"));
317                bos.write(ourSampleMessage.getBytes("ISO-8859-2"));
318                AbstractHl7OverHttpDecoder d = new Hl7OverHttpRequestDecoder();
319
320                ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
321                SplitInputStream is = new SplitInputStream(bais, 30);
322
323                d.readHeadersAndContentsFromInputStreamAndDecode(is);
324
325                assertEquals(0, bais.available());
326                assertTrue(d.getConformanceProblems().toString(), d.getConformanceProblems().isEmpty());
327                assertEquals(Charset.forName("ISO-8859-2"), d.getCharset());
328                assertTrue(d.isCharsetExplicitlySet());
329                assertEquals("application/hl7-v2", d.getContentType());
330                assertEquals(ourSampleMessage, d.getMessage());
331                assertEquals("hello", d.getUsername());
332                assertEquals("world", d.getPassword());
333                assertEquals("/AppName", d.getPath());
334
335        }
336}