]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
b1259ee61e560a12cca38e8c262b2391ab976971
[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 \r
217             } else if (boundaryTokens.length > 2) {\r
218                 System.err.println("WARNING: too many tokens after boundary= on Content-Type: header line: " + headerLine);\r
219             }\r
220         }\r
221         return boundary;\r
222     }\r
223 \r
224     /** places the boundary on the HttpTraffic in parameter object if boundary found in header "Content-Type:".\r
225      *  @return the index of the NEXT line the caller should read. */\r
226     protected static int readHeaders(HttpTraffic traffic, String[]lines, int i){\r
227         int lineCount = lines.length;\r
228         String line, lineUP;\r
229         // Now read headers until we are ready for payload or parts.\r
230         while (i<lineCount){\r
231             line = lines[i];\r
232             if (line.trim().length()==0){  //blank line seen: end of headers.\r
233                 i++;\r
234                 break;\r
235             } else {  //still reading outer headers.\r
236                 lineUP = line.toUpperCase().trim();\r
237                 if (lineUP.startsWith("CONTENT-TYPE:")){\r
238                     String[] boundaryTokens = line.split("boundary=");\r
239                     if (boundaryTokens.length == 2){\r
240                         traffic.boundary = killTrailingWS(boundaryTokens[1]);\r
241 \r
242                     } else if (boundaryTokens.length > 2){\r
243                         System.err.println("WARNING: too many tokens after boundary= on Content-Type: header line: "+line);\r
244                     }\r
245                 } else if (lineUP.startsWith("LOCATION: ")){\r
246                     traffic.location = killTrailingWS(line.substring("LOCATION: ".length()));\r
247                 } else if (lineUP.startsWith("CONTENT-LENGTH: ")){\r
248                     traffic.contentLength = Integer.parseInt(killTrailingWS(line.substring("CONTENT-LENGTH: ".length())));\r
249                 }\r
250                 i++;\r
251             }\r
252         }\r
253         return i;\r
254     }\r
255 \r
256 \r
257     //  0  1  2  3\r
258     //  a  b  c  \r\r
259 \r
260     private static String killTrailingWS(String s){\r
261         int i = s.length();\r
262         while (i>0){\r
263             char c = s.charAt(i-1);\r
264             if (c=='\r' || c=='\n' || c==' '){\r
265                 i--;\r
266                 continue;\r
267             } else {\r
268                 break;\r
269             }\r
270         }\r
271         return s.substring(0, i);\r
272     }\r
273 \r
274     public static HttpTraffic readPayloads(String fullPayload, String boundary, long contentLength){\r
275         HttpTraffic traffic = new HttpTraffic();\r
276         traffic.contentLength = contentLength;\r
277         traffic.boundary = boundary;\r
278         String [] lines = fullPayload.split("\\n", -1);\r
279         readPayloads(traffic, lines, 0);\r
280         return traffic;\r
281     }\r
282 \r
283     protected static int readPayloads(HttpTraffic traffic, String[]lines, int i){\r
284         if (traffic.boundary.length()<=0){   //END of headers, and no boundary, so read remaining and return.\r
285             if (traffic.contentLength == 0){\r
286                 return i;\r
287             }\r
288             Part part = new Part("");\r
289             traffic.payloads.add(part);\r
290             i = part.readRemaining(lines, i, traffic.contentLength);\r
291             return i;\r
292         }\r
293         int lineCount = lines.length;\r
294         String line;\r
295         while (i<lineCount){\r
296             //rest of message is payloads.\r
297             line = lines[i];\r
298 \r
299             if (line.startsWith( DD + traffic.boundary + DD )){   //this is the ending boundary.\r
300                 //close and accept payload chunk.\r
301                 i++;  //bump past last boundary.  There might be more traffic after this.\r
302                 return i;\r
303             } else if (line.startsWith(DD + traffic.boundary)){   //this is a first or middle boundary, but not last boundary.\r
304                 i++;  //bump past boundary\r
305                 //begin payload chunk\r
306                 Part part = new Part(traffic.boundary);\r
307                 traffic.payloads.add(part);\r
308                 i = part.readPart(lines, i);\r
309             } else {\r
310                 return i;\r
311                 //if (line.trim().length()>0){\r
312                 //    System.err.println("********** Skipping line: "+line); //either parser error, or something is outside of a boundary.\r
313                 //}\r
314                 //i++;\r
315             }\r
316         }\r
317         return i;\r
318     }\r
319 \r
320          \r
321     private HttpTraffic parseForward(String forward, int nexti){\r
322         HttpTraffic forwardTraffic = new HttpTraffic();\r
323         forwardTraffic.isRequest = true;\r
324         forwardTraffic.ID = getID();\r
325         //String[] lines = forward.split("\\r\\n", -1);\r
326         String[] lines = forward.split("\\n", -1);\r
327         int lineCount = lines.length;\r
328         String line;\r
329         int i = nexti;\r
330 \r
331         // Read the first line, and figure out if GET, POST, etc., and the URI\r
332         line = lines[i];\r
333         while (line.trim().length()==0){\r
334             i++;\r
335             if (i>=lineCount-1){\r
336                 return null;\r
337             }\r
338             line = lines[i];\r
339         }\r
340         String[] tokens = line.split(" ", -1);\r
341         forwardTraffic.method = tokens[0];\r
342         String urlString = tokens[1];\r
343         String[] urlHalves = urlString.split("\\?", -1); //look for a query string of the form /foo/bar?param=baz and break on question mark.\r
344         forwardTraffic.url = urlHalves[0];\r
345         if (urlHalves.length > 1){\r
346             forwardTraffic.queryParams = urlHalves[1];\r
347         }\r
348         i++;\r
349 \r
350         //if (forwardTraffic.method.equals("GET")|| forwardTraffic.method.equals("DELETE")){\r
351         //    return forwardTraffic;\r
352         //}\r
353         // Now read headers until we are ready for payload or parts.\r
354         i = readHeaders(forwardTraffic, lines, i);\r
355 \r
356         /*\r
357         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
358 \r
359             //there are more lines, but content-length header was zero,\r
360             // this means we are getting keep-alive bunches of DELETEs or OKs back.\r
361             System.err.println("###### extra requests in this one."+getID());\r
362             String filename = getID()+'_'+forwardTraffic.method+'_'+forwardTraffic.url.replaceAll("/", "_")+".requests";\r
363             saveFile("./xml", filename, forward);\r
364             return forwardTraffic;\r
365         }\r
366         */\r
367 \r
368         // We are past headers now. The rest of message is payloads.\r
369         i = readPayloads(forwardTraffic, lines, i);  //messes with forwardTraffic and places parts in it.\r
370         forwardTraffic.nexti = i;\r
371         return forwardTraffic;\r
372     }\r
373 \r
374     private HttpTraffic parseReverse(String reverse, int nexti){\r
375         HttpTraffic reverseTraffic = new HttpTraffic();\r
376         reverseTraffic.isRequest = false;\r
377         reverseTraffic.ID = getID();\r
378         //String[] lines = reverse.split("\\r\\n", -1);\r
379         String[] lines = reverse.split("\\n", -1);\r
380         int lineCount = lines.length;\r
381         String line;\r
382         int i = nexti;\r
383         if (i>=lineCount){\r
384             return null;\r
385         }\r
386         line = lines[i];\r
387                    \r
388         // Read the first line, and figure out response code, message.\r
389         while (i<lineCount){\r
390             if (line.startsWith("HTTP/1.1")){\r
391                 break;\r
392             }\r
393             i++;\r
394             line = lines[i];\r
395         }\r
396         String[] tokens = line.split(" ", 3);\r
397         String HTTP11 = tokens[0];\r
398         reverseTraffic.responseCode = Integer.parseInt(tokens[1]);\r
399         reverseTraffic.message = killTrailingWS(tokens[2]);\r
400         i++;  // done reading first line. Bump past first line.\r
401 \r
402         //if (forwardResult.message.equals("OK")){\r
403         //    return forwardResult;\r
404         //}\r
405 \r
406         // Now read headers until we are ready for payload or parts.\r
407         i = readHeaders(reverseTraffic, lines, i);\r
408 \r
409         /*\r
410         if ( (i<lines.length-1) && (reverseTraffic.contentLength==0) ) {\r
411             //there are more lines, but content-length header was zero,\r
412             // this means we are getting keep-alive bunches of DELETEs or OKs back.\r
413             System.err.println("###### extra responses in this one."+id);\r
414             String filename = getID()+".reponses";\r
415             saveFile("./xml", filename, reverse);\r
416             reverseTraffic.extra = true;\r
417             return reverseTraffic;\r
418         }\r
419         */\r
420         // We are past headers now. The rest of message is payloads.\r
421         i = readPayloads(reverseTraffic, lines, i);  //messes with forwardResult and places parts in it.\r
422         reverseTraffic.nexti = i;\r
423         if (i>=lineCount){\r
424             reverseTraffic.nexti = -1;\r
425         }\r
426         return reverseTraffic;\r
427     }\r
428 \r
429     private List<HttpTraffic> handleTcpDump(String dump){\r
430         int i = 0;\r
431         int trafficID = 0;\r
432         List<HttpTraffic> trafficList = new ArrayList<HttpTraffic>();\r
433         while (i>-1){\r
434             trafficID++;\r
435             HttpTraffic forward = parseForward(dump, i);\r
436             if (forward==null) break;\r
437             i = forward.nexti;\r
438             forward.ID = ""+trafficID;\r
439             if (forward.payloads.size()>0){\r
440                 saveForwardFiles(forward);\r
441             }\r
442             trafficList.add(forward);\r
443 \r
444             HttpTraffic reverse = parseReverse(dump, i);\r
445             if (reverse==null) break;\r
446             reverse.ID = ""+trafficID;\r
447             i = reverse.nexti;\r
448             if (reverse.payloads.size()>0){\r
449                 saveReverseFiles(reverse);\r
450             }\r
451             trafficList.add(reverse);\r
452         }\r
453         return trafficList;\r
454     }\r
455 \r
456     public static File saveFile(String dir, String relativeName, String content){\r
457         File result = null;\r
458         PrintWriter writer;\r
459         try{\r
460             result = new File(dir, relativeName);\r
461             writer = new PrintWriter(new FileOutputStream(result));\r
462         }catch (Exception e){\r
463             System.out.println("Can't write to file in saveFile: " + relativeName + "  \r\n" + e);\r
464             return null;\r
465         }\r
466         writer.write(content);\r
467         writer.close();\r
468         return result;\r
469     }\r
470     \r
471     private void saveForwardFiles(HttpTraffic fr){\r
472         for (Part part : fr.payloads){\r
473             String body = part.buffer.toString();\r
474             if (body.trim().length()==0){\r
475                 continue;\r
476             }\r
477             String filename = fr.ID+'_'+fr.method+'_'+fr.url.replaceAll("/", "_")+'_'+part.label+".xml";\r
478             filename = filename.replaceAll("/", "_");\r
479             System.out.println("trying to save file: "+filename+" :: "+fr);\r
480             part.filename = filename;\r
481             saveFile("./xml", filename, body);\r
482         }\r
483     }\r
484     \r
485     private void saveReverseFiles(HttpTraffic fr){\r
486         for (Part part : fr.payloads){\r
487             String body = part.buffer.toString();\r
488             if (body.trim().length()==0){\r
489                 continue;\r
490             }\r
491             String filename = fr.ID+'_'+fr.method+'_'+fr.url.replaceAll("/", "_");\r
492             if (part.label.length()==0){\r
493                 if (body.trim().startsWith("<?xml")){\r
494                     filename = filename + "_res.xml";\r
495                     part.filetype = "xml";\r
496                 } else {\r
497                     filename = filename + "_res.txt";\r
498                     part.filetype = "txt";\r
499                 }\r
500             } else {\r
501                 filename = filename + '_'+part.label+"_res.xml";\r
502                 part.filetype = "xml";\r
503             }\r
504             filename = filename.replaceAll("/", "_");\r
505             System.out.println("trying to save file: "+filename+" :: "+fr);\r
506             part.filename = filename;\r
507             saveFile("./xml", filename, body);\r
508         }\r
509     }\r
510 \r
511     public static String readFile(String dir, String relPath) throws Exception{\r
512         File theFile = new File(dir, relPath);\r
513         FileInputStream fis = new FileInputStream(theFile);\r
514         byte[] theData = new byte[(int) theFile.length()];\r
515         // need to check the number of bytes read here\r
516         int howmany = fis.read(theData);\r
517         fis.close();\r
518         return new String(theData);\r
519     }\r
520 \r
521     public static List<HttpTraffic> process(String httpSessionTraffic){\r
522         PayloadLogger pll = new PayloadLogger();\r
523         List<HttpTraffic> trafficList = pll.handleTcpDump(httpSessionTraffic);\r
524         return trafficList;\r
525     }\r
526 \r
527     public static void main(String[]args) throws Exception {\r
528         String dump = readFile(".", args[0]);\r
529         PayloadLogger pll = new PayloadLogger();\r
530         List<HttpTraffic> trafficList = pll.handleTcpDump(dump);\r
531         reporter.finished(trafficList);\r
532         saveReport();\r
533     }\r
534 \r
535     \r
536 }