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