]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
ec11df9cf2e94a5a0a244e1db0dd94a09d37c09f
[tmp/jakarta-migration.git] /
1 /**\r
2  * This document is a part of the source code and related artifacts\r
3  * for CollectionSpace, an open source collections management system\r
4  * for museums and related institutions:\r
5  *\r
6  * http://www.collectionspace.org\r
7  * http://wiki.collectionspace.org\r
8  *\r
9  * Copyright (c) 2009 Regents of the University of California\r
10  *\r
11  * Licensed under the Educational Community License (ECL), Version 2.0.\r
12  * You may not use this file except in compliance with this License.\r
13  *\r
14  * You may obtain a copy of the ECL 2.0 License at\r
15  * https://source.collectionspace.org/collection-space/LICENSE.txt\r
16  *\r
17  *  Unless required by applicable law or agreed to in writing, software\r
18  *  distributed under the License is distributed on an "AS IS" BASIS,\r
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
20  *  See the License for the specific language governing permissions and\r
21  *  limitations under the License.\r
22  */\r
23 \r
24 package org.collectionspace.services.IntegrationTests.xmlreplay;\r
25 \r
26 import java.io.*;\r
27 import java.util.ArrayList;\r
28 import java.util.List;\r
29 \r
30 public class PayloadLogger{\r
31 \r
32     public static void saveReport(){\r
33         reporter.writeTable();\r
34     }\r
35 \r
36     private static Reporter reporter = new Reporter();\r
37 \r
38     private static volatile int ID = 1000;\r
39     public String getID(){\r
40         return ""+ID;\r
41     }\r
42 \r
43     private static String DD = "--";\r
44     private static String LABEL="LABEL: ";\r
45 \r
46     static class Reporter {\r
47         public Reporter(){\r
48             table.append("<html><body><table border='1'>\r\n");\r
49         }\r
50         public static final String START = "<tr><td>";\r
51         public static final String SEP = "</td><td>";\r
52         public static final String END = "</td></tr>";\r
53 \r
54         public void writeTable(){\r
55             table.append("</table></body></html>");\r
56             saveFile("./xml/", "results.html", table.toString());\r
57         }\r
58 \r
59         private StringBuffer table = new StringBuffer();\r
60 \r
61         public synchronized void finished(HttpTraffic traffic){\r
62             String direction = traffic.isRequest ?\r
63                                 "<span style='background-color: lightgreen;'>==&gt;</span>"\r
64                                 :\r
65                                 " &lt;==";\r
66             table.append(START)\r
67                     .append(direction)\r
68                     .append(SEP)\r
69                     .append(traffic==null ? "null" : traffic.toRow(SEP, this))\r
70                     .append(END);\r
71         }\r
72 \r
73         public synchronized void finished(List<HttpTraffic> trafficList){\r
74             for (HttpTraffic traffic: trafficList){\r
75                 finished(traffic);\r
76             }\r
77         }\r
78 \r
79         public static String link(String desc, String url){\r
80             return "<a href='"+url+"'>"+desc+"</a>";\r
81         }\r
82         public static final String newline = "<br />\r\n";\r
83 \r
84     }\r
85 \r
86 \r
87     static class HttpTraffic {\r
88         public HttpTraffic(){\r
89             payloads = new ArrayList<Part>();\r
90         }\r
91         public List<Part> payloads;\r
92         public String method = "";\r
93         public String url = "";\r
94         public String queryParams = "";\r
95         public String message = "";\r
96         public int responseCode = 0;\r
97         public String boundary = "";\r
98         public String location = "";\r
99         public long contentLength = -1;\r
100         public boolean isRequest = true;\r
101         public boolean extra = false;\r
102         public String ID = "0";\r
103         public int nexti = 0;\r
104 \r
105         public Part getPart(String label){\r
106             for (Part part : payloads){\r
107                 if (part.label.equalsIgnoreCase(label)){\r
108                     return part;\r
109                 }\r
110             }\r
111             return null;\r
112         }\r
113 \r
114         public String toRow(String sep, Reporter reporter){\r
115             StringBuffer b = new StringBuffer();\r
116             for (Part part : payloads){\r
117                 String name = part.label;\r
118                 if (part.filename.length()==0){\r
119                     continue;\r
120                 }\r
121                 if (name.trim().length()<=0){\r
122                     name = ID;\r
123                 }\r
124                 name = name+" ("+part.filetype+')';\r
125                 String link = reporter.link(name, part.filename);\r
126                 b.append(link)\r
127                  .append(reporter.newline);\r
128             }\r
129             String parts = b.toString();\r
130             if (isRequest){\r
131                 return  ID+sep\r
132                         +method+sep\r
133                         +url+sep\r
134                         +queryParams+sep\r
135                         +sep\r
136                         +parts;\r
137             } else {\r
138                 return  ID+sep\r
139                         +responseCode+sep\r
140                         +message+sep\r
141                         +location+sep\r
142                         +contentLength+sep\r
143                         +url\r
144                         +parts;\r
145             }\r
146         }\r
147     }\r
148 \r
149     static class Part {\r
150         public Part(String boundary){\r
151             this.boundary = boundary;\r
152         }\r
153         public boolean isMultipart(){\r
154             return boundary.length()>0;\r
155         }\r
156         public String toString(){\r
157             return "Part:"+label+";";\r
158         }\r
159         public String filename = "";\r
160         public String filetype = "";\r
161         public String boundary;\r
162         public StringBuffer buffer = new StringBuffer();\r
163         public String getContent(){\r
164             return buffer.toString();\r
165         }\r
166         public String label = "";\r
167         public int readPart(String[]lines, int i){\r
168             String line = "";\r
169             boolean readingPartHeaders = true;\r
170             while(readingPartHeaders){\r
171                 line = killTrailingWS(lines[i]);\r
172                 if (line.toUpperCase().startsWith(LABEL)){\r
173                     this.label = line.substring(LABEL.length()).trim();\r
174                 } else if (line.trim().length()==0){\r
175                     readingPartHeaders = false;\r
176                 }\r
177                 i++;\r
178             }\r
179             while (i<lines.length){\r
180                 line = lines[i];\r
181                 if (line.startsWith(DD+boundary)){\r
182                     return i;   \r
183                 }\r
184                 this.buffer.append(line).append("\r\n");   //todo: maybe don't add CRLF on last line.\r
185                 i++;\r
186             }\r
187             return i;               \r
188         }\r
189         public int readRemaining(String [] lines, int i, long contentLength){\r
190             String line;\r
191             int bytesRead=0;\r
192             while (i<lines.length && bytesRead<contentLength){\r
193                 line = killTrailingWS(lines[i]);\r
194                 if (line.startsWith("HTTP/1.1")){\r
195                     return i;\r
196                 }\r
197                 int read = line.length();\r
198                 bytesRead += read;\r
199                 buffer.append(line).append("\r\n");   //todo: maybe don't add CRLF on last line.\r
200                 i++;\r
201             }\r
202             return i;\r
203         }\r
204     }\r
205 \r
206     public static String parseBoundary(String headerLine) {\r
207         if (Tools.isEmpty(headerLine)) {\r
208             return "";\r
209         }\r
210         String lineUP = headerLine.toUpperCase();\r
211         String boundary = "";\r
212         if (lineUP.startsWith("CONTENT-TYPE:")) {\r
213             String[] boundaryTokens = headerLine.split("boundary=");\r
214             if (boundaryTokens.length == 2) {\r
215                 boundary = killTrailingWS(boundaryTokens[1]);\r
216                 //Header might be:\r
217                 // Content-Type: multipart/mixed; boundary=a97c20ab-3ef6-4adc-82b0-6cf28c450faf;charset=ISO-8859-1\r
218 \r
219                 String[] boundaryTerm = boundary.split(";");\r
220                 boundary = boundaryTerm[0];\r
221 \r
222             } else if (boundaryTokens.length > 2) {\r
223                 System.err.println("WARNING: too many tokens after boundary= on Content-Type: header line: " + headerLine);\r
224             }\r
225         }\r
226         return boundary;\r
227     }\r
228 \r
229     /** places the boundary on the HttpTraffic in parameter object if boundary found in header "Content-Type:".\r
230      *  @return the index of the NEXT line the caller should read. */\r
231     protected static int readHeaders(HttpTraffic traffic, String[]lines, int i){\r
232         int lineCount = lines.length;\r
233         String line, lineUP;\r
234         // Now read headers until we are ready for payload or parts.\r
235         while (i<lineCount){\r
236             line = lines[i];\r
237             if (line.trim().length()==0){  //blank line seen: end of headers.\r
238                 i++;\r
239                 break;\r
240             } else {  //still reading outer headers.\r
241                 lineUP = line.toUpperCase().trim();\r
242                 if (lineUP.startsWith("CONTENT-TYPE:")){\r
243                     String[] boundaryTokens = line.split("boundary=");\r
244                     if (boundaryTokens.length == 2){\r
245                         traffic.boundary = killTrailingWS(boundaryTokens[1]);\r
246 \r
247                     } else if (boundaryTokens.length > 2){\r
248                         System.err.println("WARNING: too many tokens after boundary= on Content-Type: header line: "+line);\r
249                     }\r
250                 } else if (lineUP.startsWith("LOCATION: ")){\r
251                     traffic.location = killTrailingWS(line.substring("LOCATION: ".length()));\r
252                 } else if (lineUP.startsWith("CONTENT-LENGTH: ")){\r
253                     traffic.contentLength = Integer.parseInt(killTrailingWS(line.substring("CONTENT-LENGTH: ".length())));\r
254                 }\r
255                 i++;\r
256             }\r
257         }\r
258         return i;\r
259     }\r
260 \r
261 \r
262     //  0  1  2  3\r
263     //  a  b  c  \r\r
264 \r
265     private static String killTrailingWS(String s){\r
266         int i = s.length();\r
267         while (i>0){\r
268             char c = s.charAt(i-1);\r
269             if (c=='\r' || c=='\n' || c==' '){\r
270                 i--;\r
271                 continue;\r
272             } else {\r
273                 break;\r
274             }\r
275         }\r
276         return s.substring(0, i);\r
277     }\r
278 \r
279     public static HttpTraffic readPayloads(String fullPayload, String boundary, long contentLength){\r
280         HttpTraffic traffic = new HttpTraffic();\r
281         traffic.contentLength = contentLength;\r
282         traffic.boundary = boundary;\r
283         String [] lines = fullPayload.split("\\n", -1);\r
284         readPayloads(traffic, lines, 0);\r
285         return traffic;\r
286     }\r
287 \r
288     protected static int readPayloads(HttpTraffic traffic, String[]lines, int i){\r
289         if (traffic.boundary.length()<=0){   //END of headers, and no boundary, so read remaining and return.\r
290             if (traffic.contentLength == 0){\r
291                 return i;\r
292             }\r
293             Part part = new Part("");\r
294             traffic.payloads.add(part);\r
295             i = part.readRemaining(lines, i, traffic.contentLength);\r
296             return i;\r
297         }\r
298         int lineCount = lines.length;\r
299         String line;\r
300         while (i<lineCount){\r
301             //rest of message is payloads.\r
302             line = lines[i];\r
303 \r
304             if (line.startsWith( DD + traffic.boundary + DD )){   //this is the ending boundary.\r
305                 //close and accept payload chunk.\r
306                 i++;  //bump past last boundary.  There might be more traffic after this.\r
307                 return i;\r
308             } else if (line.startsWith(DD + traffic.boundary)){   //this is a first or middle boundary, but not last boundary.\r
309                 i++;  //bump past boundary\r
310                 //begin payload chunk\r
311                 Part part = new Part(traffic.boundary);\r
312                 traffic.payloads.add(part);\r
313                 i = part.readPart(lines, i);\r
314             } else {\r
315                 return i;\r
316                 //if (line.trim().length()>0){\r
317                 //    System.err.println("********** Skipping line: "+line); //either parser error, or something is outside of a boundary.\r
318                 //}\r
319                 //i++;\r
320             }\r
321         }\r
322         return i;\r
323     }\r
324 \r
325          \r
326     private HttpTraffic parseForward(String forward, int nexti){\r
327         HttpTraffic forwardTraffic = new HttpTraffic();\r
328         forwardTraffic.isRequest = true;\r
329         forwardTraffic.ID = getID();\r
330         //String[] lines = forward.split("\\r\\n", -1);\r
331         String[] lines = forward.split("\\n", -1);\r
332         int lineCount = lines.length;\r
333         String line;\r
334         int i = nexti;\r
335 \r
336         // Read the first line, and figure out if GET, POST, etc., and the URI\r
337         line = lines[i];\r
338         while (line.trim().length()==0){\r
339             i++;\r
340             if (i>=lineCount-1){\r
341                 return null;\r
342             }\r
343             line = lines[i];\r
344         }\r
345         String[] tokens = line.split(" ", -1);\r
346         forwardTraffic.method = tokens[0];\r
347         String urlString = tokens[1];\r
348         String[] urlHalves = urlString.split("\\?", -1); //look for a query string of the form /foo/bar?param=baz and break on question mark.\r
349         forwardTraffic.url = urlHalves[0];\r
350         if (urlHalves.length > 1){\r
351             forwardTraffic.queryParams = urlHalves[1];\r
352         }\r
353         i++;\r
354 \r
355         //if (forwardTraffic.method.equals("GET")|| forwardTraffic.method.equals("DELETE")){\r
356         //    return forwardTraffic;\r
357         //}\r
358         // Now read headers until we are ready for payload or parts.\r
359         i = readHeaders(forwardTraffic, lines, i);\r
360 \r
361         /*\r
362         if ( (i<lines.length-1) && (forwardTraffic.contentLength<=0) ) {  //0 means a 0 was seen, -1 means no header was seen, as will be the case in GET or DELETE.\r
363 \r
364             //there are more lines, but content-length header was zero,\r
365             // this means we are getting keep-alive bunches of DELETEs or OKs back.\r
366             System.err.println("###### extra requests in this one."+getID());\r
367             String filename = getID()+'_'+forwardTraffic.method+'_'+forwardTraffic.url.replaceAll("/", "_")+".requests";\r
368             saveFile("./xml", filename, forward);\r
369             return forwardTraffic;\r
370         }\r
371         */\r
372 \r
373         // We are past headers now. The rest of message is payloads.\r
374         i = readPayloads(forwardTraffic, lines, i);  //messes with forwardTraffic and places parts in it.\r
375         forwardTraffic.nexti = i;\r
376         return forwardTraffic;\r
377     }\r
378 \r
379     private HttpTraffic parseReverse(String reverse, int nexti){\r
380         HttpTraffic reverseTraffic = new HttpTraffic();\r
381         reverseTraffic.isRequest = false;\r
382         reverseTraffic.ID = getID();\r
383         //String[] lines = reverse.split("\\r\\n", -1);\r
384         String[] lines = reverse.split("\\n", -1);\r
385         int lineCount = lines.length;\r
386         String line;\r
387         int i = nexti;\r
388         if (i>=lineCount){\r
389             return null;\r
390         }\r
391         line = lines[i];\r
392                    \r
393         // Read the first line, and figure out response code, message.\r
394         while (i<lineCount){\r
395             if (line.startsWith("HTTP/1.1")){\r
396                 break;\r
397             }\r
398             i++;\r
399             line = lines[i];\r
400         }\r
401         String[] tokens = line.split(" ", 3);\r
402         String HTTP11 = tokens[0];\r
403         reverseTraffic.responseCode = Integer.parseInt(tokens[1]);\r
404         reverseTraffic.message = killTrailingWS(tokens[2]);\r
405         i++;  // done reading first line. Bump past first line.\r
406 \r
407         //if (forwardResult.message.equals("OK")){\r
408         //    return forwardResult;\r
409         //}\r
410 \r
411         // Now read headers until we are ready for payload or parts.\r
412         i = readHeaders(reverseTraffic, lines, i);\r
413 \r
414         /*\r
415         if ( (i<lines.length-1) && (reverseTraffic.contentLength==0) ) {\r
416             //there are more lines, but content-length header was zero,\r
417             // this means we are getting keep-alive bunches of DELETEs or OKs back.\r
418             System.err.println("###### extra responses in this one."+id);\r
419             String filename = getID()+".reponses";\r
420             saveFile("./xml", filename, reverse);\r
421             reverseTraffic.extra = true;\r
422             return reverseTraffic;\r
423         }\r
424         */\r
425         // We are past headers now. The rest of message is payloads.\r
426         i = readPayloads(reverseTraffic, lines, i);  //messes with forwardResult and places parts in it.\r
427         reverseTraffic.nexti = i;\r
428         if (i>=lineCount){\r
429             reverseTraffic.nexti = -1;\r
430         }\r
431         return reverseTraffic;\r
432     }\r
433 \r
434     private List<HttpTraffic> handleTcpDump(String dump){\r
435         int i = 0;\r
436         int trafficID = 0;\r
437         List<HttpTraffic> trafficList = new ArrayList<HttpTraffic>();\r
438         while (i>-1){\r
439             trafficID++;\r
440             HttpTraffic forward = parseForward(dump, i);\r
441             if (forward==null) break;\r
442             i = forward.nexti;\r
443             forward.ID = ""+trafficID;\r
444             if (forward.payloads.size()>0){\r
445                 saveForwardFiles(forward);\r
446             }\r
447             trafficList.add(forward);\r
448 \r
449             HttpTraffic reverse = parseReverse(dump, i);\r
450             if (reverse==null) break;\r
451             reverse.ID = ""+trafficID;\r
452             i = reverse.nexti;\r
453             if (reverse.payloads.size()>0){\r
454                 saveReverseFiles(reverse);\r
455             }\r
456             trafficList.add(reverse);\r
457         }\r
458         return trafficList;\r
459     }\r
460 \r
461     public static File saveFile(String dir, String relativeName, String content){\r
462         File result = null;\r
463         PrintWriter writer;\r
464         try{\r
465             result = new File(dir, relativeName);\r
466             writer = new PrintWriter(new FileOutputStream(result));\r
467         }catch (Exception e){\r
468             System.out.println("Can't write to file in saveFile: " + relativeName + "  \r\n" + e);\r
469             return null;\r
470         }\r
471         writer.write(content);\r
472         writer.close();\r
473         return result;\r
474     }\r
475     \r
476     private void saveForwardFiles(HttpTraffic fr){\r
477         for (Part part : fr.payloads){\r
478             String body = part.buffer.toString();\r
479             if (body.trim().length()==0){\r
480                 continue;\r
481             }\r
482             String filename = fr.ID+'_'+fr.method+'_'+fr.url.replaceAll("/", "_")+'_'+part.label+".xml";\r
483             filename = filename.replaceAll("/", "_");\r
484             System.out.println("trying to save file: "+filename+" :: "+fr);\r
485             part.filename = filename;\r
486             saveFile("./xml", filename, body);\r
487         }\r
488     }\r
489     \r
490     private void saveReverseFiles(HttpTraffic fr){\r
491         for (Part part : fr.payloads){\r
492             String body = part.buffer.toString();\r
493             if (body.trim().length()==0){\r
494                 continue;\r
495             }\r
496             String filename = fr.ID+'_'+fr.method+'_'+fr.url.replaceAll("/", "_");\r
497             if (part.label.length()==0){\r
498                 if (body.trim().startsWith("<?xml")){\r
499                     filename = filename + "_res.xml";\r
500                     part.filetype = "xml";\r
501                 } else {\r
502                     filename = filename + "_res.txt";\r
503                     part.filetype = "txt";\r
504                 }\r
505             } else {\r
506                 filename = filename + '_'+part.label+"_res.xml";\r
507                 part.filetype = "xml";\r
508             }\r
509             filename = filename.replaceAll("/", "_");\r
510             System.out.println("trying to save file: "+filename+" :: "+fr);\r
511             part.filename = filename;\r
512             saveFile("./xml", filename, body);\r
513         }\r
514     }\r
515 \r
516     public static String readFile(String dir, String relPath) throws Exception{\r
517         File theFile = new File(dir, relPath);\r
518         FileInputStream fis = new FileInputStream(theFile);\r
519         byte[] theData = new byte[(int) theFile.length()];\r
520         // need to check the number of bytes read here\r
521         int howmany = fis.read(theData);\r
522         fis.close();\r
523         return new String(theData);\r
524     }\r
525 \r
526     public static List<HttpTraffic> process(String httpSessionTraffic){\r
527         PayloadLogger pll = new PayloadLogger();\r
528         List<HttpTraffic> trafficList = pll.handleTcpDump(httpSessionTraffic);\r
529         return trafficList;\r
530     }\r
531 \r
532     public static void main(String[]args) throws Exception {\r
533         String dump = readFile(".", args[0]);\r
534         PayloadLogger pll = new PayloadLogger();\r
535         List<HttpTraffic> trafficList = pll.handleTcpDump(dump);\r
536         reporter.finished(trafficList);\r
537         saveReport();\r
538     }\r
539 \r
540     \r
541 }