1
2
3
4
5
6
7 package org.mule.transport.http;
8
9 import org.mule.api.MuleEvent;
10 import org.mule.api.MuleMessage;
11 import org.mule.api.expression.ExpressionManager;
12
13 import java.net.URI;
14 import java.net.URISyntaxException;
15 import java.text.SimpleDateFormat;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Locale;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.TimeZone;
25
26 import org.apache.commons.httpclient.Cookie;
27 import org.apache.commons.httpclient.Header;
28 import org.apache.commons.httpclient.HttpClient;
29 import org.apache.commons.httpclient.cookie.CookiePolicy;
30 import org.apache.commons.httpclient.cookie.CookieSpec;
31 import org.apache.commons.httpclient.cookie.MalformedCookieException;
32 import org.apache.commons.httpclient.cookie.NetscapeDraftSpec;
33 import org.apache.commons.httpclient.cookie.RFC2109Spec;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.tomcat.util.http.Cookies;
37 import org.apache.tomcat.util.http.MimeHeaders;
38 import org.apache.tomcat.util.http.ServerCookie;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 public class CookieHelper
101 {
102
103
104
105
106
107 private static final String DEFAULT_URI_STRING = "http://localhost:80/";
108
109
110
111
112 protected static final Log logger = LogFactory.getLog(CookieHelper.class);
113
114 private static final String EXPIRE_PATTERN = "EEE, d-MMM-yyyy HH:mm:ss z";
115 private static final SimpleDateFormat EXPIRE_FORMATTER;
116
117 static
118 {
119 EXPIRE_FORMATTER = new SimpleDateFormat(EXPIRE_PATTERN, Locale.US);
120 EXPIRE_FORMATTER.setTimeZone(TimeZone.getTimeZone("GMT"));
121 }
122
123
124
125
126 private CookieHelper()
127 {
128
129 }
130
131
132
133
134
135 public static CookieSpec getCookieSpec(String spec)
136 {
137 if (spec != null && spec.equalsIgnoreCase(HttpConnector.COOKIE_SPEC_NETSCAPE))
138 {
139 return new NetscapeDraftSpec();
140 }
141 else
142 {
143 return new RFC2109Spec();
144 }
145 }
146
147
148
149
150
151 public static String getCookiePolicy(String spec)
152 {
153 if (spec != null && spec.equalsIgnoreCase(HttpConnector.COOKIE_SPEC_NETSCAPE))
154 {
155 return CookiePolicy.NETSCAPE;
156 }
157 else
158 {
159 return CookiePolicy.RFC_2109;
160 }
161 }
162
163
164
165
166 public static Cookie[] parseCookiesAsAClient(Header cookieHeader, String spec)
167 throws MalformedCookieException
168 {
169 return parseCookiesAsAClient(cookieHeader.getValue(), spec, null);
170 }
171
172
173
174
175 public static Cookie[] parseCookiesAsAClient(String cookieHeaderValue, String spec)
176 throws MalformedCookieException
177 {
178 return parseCookiesAsAClient(cookieHeaderValue, spec, null);
179 }
180
181
182
183
184 public static Cookie[] parseCookiesAsAClient(Header cookieHeader, String spec, URI uri)
185 throws MalformedCookieException
186 {
187 return parseCookiesAsAClient(cookieHeader.getValue(), spec, uri);
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202 public static Cookie[] parseCookiesAsAClient(String cookieHeaderValue, String spec, URI uri)
203 throws MalformedCookieException
204 {
205 if (uri == null)
206 {
207 try
208 {
209 uri = new URI(DEFAULT_URI_STRING);
210 }
211 catch (URISyntaxException e)
212 {
213 throw new RuntimeException("This should have not happened", e);
214 }
215 }
216 CookieSpec cookieSpec = getCookieSpec(spec);
217 boolean secure = uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("https");
218 String host = uri.getHost();
219 int port = getPortFromURI(uri);
220 String path = uri.getPath();
221
222 return cookieSpec.parse(host, port, path, secure, cookieHeaderValue);
223 }
224
225 private static int getPortFromURI(URI uri) throws MalformedCookieException
226 {
227 int port = uri.getPort();
228 if (port < 0)
229 {
230 String scheme = uri.getScheme();
231 if (scheme.equalsIgnoreCase("https"))
232 {
233 port = 443;
234 }
235 else if (scheme.equalsIgnoreCase("http"))
236 {
237 port = 80;
238 }
239 else
240 {
241 String message = String.format(
242 "The uri (%1s) does not specify a port and no default is available for its scheme (%2s).",
243 uri, scheme);
244 throw new MalformedCookieException(message);
245 }
246 }
247 return port;
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261 public static Cookie[] parseCookiesAsAServer(Header header, URI uri)
262 {
263 return parseCookiesAsAServer(header.getValue(), uri);
264 }
265
266
267
268
269
270
271
272
273
274 public static Cookie[] parseCookiesAsAServer(String headerValue, URI uri)
275 {
276 MimeHeaders mimeHeaders = new MimeHeaders();
277 mimeHeaders.addValue(HttpConstants.HEADER_COOKIE).setBytes(headerValue.getBytes(), 0,
278 headerValue.length());
279
280 Cookies cs = new Cookies(mimeHeaders);
281 Cookie[] cookies = new Cookie[cs.getCookieCount()];
282 for (int i = 0; i < cs.getCookieCount(); i++)
283 {
284 ServerCookie serverCookie = cs.getCookie(i);
285 cookies[i] = transformServerCookieToClientCookie(serverCookie);
286 if (uri != null)
287 {
288 cookies[i].setSecure(uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("https"));
289 cookies[i].setDomain(uri.getHost());
290 cookies[i].setPath(uri.getPath());
291 }
292 }
293 return cookies;
294 }
295
296
297
298
299
300
301
302 protected static Cookie transformServerCookieToClientCookie(ServerCookie serverCookie)
303 {
304 Cookie clientCookie = new Cookie(serverCookie.getDomain().toString(), serverCookie.getName()
305 .toString(), serverCookie.getValue().toString(), serverCookie.getPath().toString(),
306 serverCookie.getMaxAge(), serverCookie.getSecure());
307 clientCookie.setComment(serverCookie.getComment().toString());
308 clientCookie.setVersion(serverCookie.getVersion());
309 return clientCookie;
310 }
311
312
313
314
315
316 public static String formatCookieForASetCookieHeader(Cookie cookie)
317 {
318 StringBuffer sb = new StringBuffer();
319 ServerCookie.appendCookieValue(sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
320 cookie.getPath(), cookie.getDomain(), cookie.getComment(), -1, cookie.getSecure());
321
322 Date expiryDate = cookie.getExpiryDate();
323 if (expiryDate != null)
324 {
325 sb.append("; Expires=");
326 sb.append(EXPIRE_FORMATTER.format(expiryDate));
327 }
328
329 return sb.toString();
330 }
331
332
333
334
335
336
337
338
339
340
341
342 public static void addCookiesToClient(HttpClient client,
343 Object cookiesObject,
344 String policy,
345 MuleEvent event,
346 URI destinationUri)
347 {
348 CookieStorageType.resolveCookieStorageType(cookiesObject).addCookiesToClient(client, cookiesObject,
349 policy, event, destinationUri);
350 }
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 public static Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue)
372 {
373 return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(
374 preExistentCookies, cookieName, cookieValue);
375 }
376
377
378
379
380
381
382
383
384
385
386
387
388
389 public static Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray)
390 {
391 return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(
392 preExistentCookies, newCookiesArray);
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407 public static Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap)
408 {
409 return CookieStorageType.resolveCookieStorageType(preExistentCookies).putAndMergeCookie(
410 preExistentCookies, newCookiesMap);
411 }
412
413
414
415
416
417 public static String getCookieValueFromCookies(Object cookiesObject, String cookieName)
418 {
419 return CookieStorageType.resolveCookieStorageType(cookiesObject).getCookieValueFromCookies(
420 cookiesObject, cookieName);
421 }
422
423
424
425
426 public static Cookie[] asArrayOfCookies(Object cookiesObject)
427 {
428 return CookieStorageType.resolveCookieStorageType(cookiesObject).asArrayOfCookies(cookiesObject);
429 }
430
431 }
432
433
434
435
436
437
438
439 enum CookieStorageType
440 {
441
442
443
444
445
446
447
448
449
450
451 ARRAY_OF_COOKIES
452 {
453 @Override
454 public Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue)
455 {
456 final Cookie[] preExistentCookiesArray = (Cookie[]) preExistentCookies;
457
458 final int sessionIndex = getCookieIndexFromCookiesArray(cookieName, preExistentCookiesArray);
459
460
461
462 final Cookie newSessionCookie = new Cookie(null, cookieName, cookieValue);
463 final Cookie[] mergedCookiesArray;
464 if (sessionIndex >= 0)
465 {
466 preExistentCookiesArray[sessionIndex] = newSessionCookie;
467 mergedCookiesArray = preExistentCookiesArray;
468 }
469 else
470 {
471 Cookie[] newSessionCookieArray = new Cookie[]{newSessionCookie};
472 mergedCookiesArray = concatenateCookies(preExistentCookiesArray, newSessionCookieArray);
473 }
474 return mergedCookiesArray;
475 }
476
477 protected Cookie[] concatenateCookies(Cookie[] cookies1, Cookie[] cookies2)
478 {
479 if (cookies1 == null)
480 {
481 return cookies2;
482 }
483 else if (cookies2 == null)
484 {
485 return null;
486 }
487 else
488 {
489 Cookie[] mergedCookies = new Cookie[cookies1.length + cookies2.length];
490 System.arraycopy(cookies1, 0, mergedCookies, 0, cookies1.length);
491 System.arraycopy(cookies2, 0, mergedCookies, cookies1.length, cookies2.length);
492 return mergedCookies;
493 }
494 }
495
496 protected int getCookieIndexFromCookiesArray(String cookieName, Cookie[] preExistentCookies)
497 {
498 if (preExistentCookies != null && cookieName != null)
499 {
500 for (int i = 0; i < preExistentCookies.length; i++)
501 {
502 if (cookieName.equals(preExistentCookies[i].getName()))
503 {
504 return i;
505 }
506 }
507 }
508 return -1;
509 }
510
511 @Override
512 public String getCookieValueFromCookies(Object cookiesObject, String cookieName)
513 {
514 Cookie[] cookies = (Cookie[]) cookiesObject;
515
516 int sessionIndex = getCookieIndexFromCookiesArray(cookieName, cookies);
517 if (sessionIndex >= 0)
518 {
519 return cookies[sessionIndex].getValue();
520 }
521 else
522 {
523 return null;
524 }
525 }
526
527 @Override
528 public void addCookiesToClient(HttpClient client,
529 Object cookiesObject,
530 String policy,
531 MuleEvent event,
532 URI destinationUri)
533 {
534 Cookie[] cookies = (Cookie[]) cookiesObject;
535
536 if (cookies != null && cookies.length > 0)
537 {
538 String host = destinationUri.getHost();
539 String path = destinationUri.getPath();
540 for (Cookie cookie : cookies)
541 {
542 client.getState().addCookie(
543 new Cookie(host, cookie.getName(), cookie.getValue(), path, cookie.getExpiryDate(),
544 cookie.getSecure()));
545 }
546 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
547 }
548 }
549
550 @Override
551 public Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray)
552 {
553 if (newCookiesArray == null)
554 {
555 return preExistentCookies;
556 }
557 final List<Cookie> cookiesThatAreReallyNew = new ArrayList<Cookie>(newCookiesArray.length);
558 final Cookie[] preExistentCookiesArray = (Cookie[]) preExistentCookies;
559 for (Cookie newCookie : newCookiesArray)
560 {
561 int newCookieInPreExistentArrayIndex = getCookieIndexFromCookiesArray(newCookie.getName(),
562 preExistentCookiesArray);
563 if (newCookieInPreExistentArrayIndex >= 0)
564 {
565
566 preExistentCookiesArray[newCookieInPreExistentArrayIndex] = newCookie;
567 }
568 else
569 {
570
571 cookiesThatAreReallyNew.add(newCookie);
572 }
573 }
574
575 return concatenateCookies(preExistentCookiesArray,
576 cookiesThatAreReallyNew.toArray(new Cookie[cookiesThatAreReallyNew.size()]));
577 }
578
579 @Override
580 public Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap)
581 {
582 if (newCookiesMap == null)
583 {
584 return putAndMergeCookie(preExistentCookies, (Cookie[]) null);
585 }
586 else
587 {
588 Cookie[] cookiesArray = new Cookie[newCookiesMap.size()];
589 int i = 0;
590 for (Entry<String, String> cookieEntry : newCookiesMap.entrySet())
591 {
592 Cookie cookie = new Cookie();
593 cookie.setName(cookieEntry.getKey());
594 cookie.setValue(cookieEntry.getValue());
595 cookiesArray[i++] = cookie;
596 }
597 return putAndMergeCookie(preExistentCookies, cookiesArray);
598 }
599 }
600
601 @Override
602 public Cookie[] asArrayOfCookies(Object cookiesObject)
603 {
604 if (cookiesObject == null)
605 {
606 return ZERO_COOKIES;
607 }
608 else
609 {
610 return (Cookie[]) cookiesObject;
611 }
612 }
613
614 },
615
616
617
618
619
620
621
622
623
624
625
626
627 MAP_STRING_STRING
628 {
629 @Override
630 @SuppressWarnings("unchecked")
631 public Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue)
632 {
633 final Map<String, String> cookieMap = (Map<String, String>) preExistentCookies;
634
635 cookieMap.put(cookieName, cookieValue);
636 return cookieMap;
637 }
638
639 @Override
640 @SuppressWarnings("unchecked")
641 public String getCookieValueFromCookies(Object cookiesObject, String cookieName)
642 {
643 return ((Map<String, String>) cookiesObject).get(cookieName);
644 }
645
646 @Override
647 @SuppressWarnings("unchecked")
648 public void addCookiesToClient(HttpClient client,
649 Object cookiesObject,
650 String policy,
651 MuleEvent event,
652 URI destinationUri)
653 {
654 Map<String, String> cookieMap = (Map<String, String>) cookiesObject;
655
656 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
657
658 String host = destinationUri.getHost();
659 String path = destinationUri.getPath();
660 Iterator<String> keyIter = cookieMap.keySet().iterator();
661 while (keyIter.hasNext())
662 {
663 String key = keyIter.next();
664 String cookieValue = cookieMap.get(key);
665
666 final String value;
667 if (event != null)
668 {
669 value = event.getMuleContext()
670 .getExpressionManager()
671 .parse(cookieValue, event.getMessage());
672 }
673 else
674 {
675 value = cookieValue;
676 }
677
678 Cookie cookie = new Cookie(host, key, value, path, null, false);
679 client.getState().addCookie(cookie);
680 }
681
682 }
683
684 @Override
685 public Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray)
686 {
687 if (newCookiesArray == null)
688 {
689 return preExistentCookies;
690 }
691 for (Cookie cookie : newCookiesArray)
692 {
693 preExistentCookies = putAndMergeCookie(preExistentCookies, cookie.getName(),
694 cookie.getValue());
695 }
696 return preExistentCookies;
697 }
698
699 @Override
700 public Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap)
701 {
702 if (newCookiesMap == null)
703 {
704 return preExistentCookies;
705 }
706 for (Entry<String, String> cookieEntry : newCookiesMap.entrySet())
707 {
708 preExistentCookies = putAndMergeCookie(preExistentCookies, cookieEntry.getKey(),
709 cookieEntry.getValue());
710 }
711 return preExistentCookies;
712 }
713
714 @Override
715 @SuppressWarnings("unchecked")
716 public Cookie[] asArrayOfCookies(Object cookiesObject)
717 {
718 Map<String, String> cookieMap = (Map<String, String>) cookiesObject;
719 Cookie[] arrayOfCookies = new Cookie[cookieMap.size()];
720 int i = 0;
721 for (Entry<String, String> cookieEntry : cookieMap.entrySet())
722 {
723 Cookie cookie = new Cookie();
724 cookie.setName(cookieEntry.getKey());
725 cookie.setValue(cookieEntry.getValue());
726 arrayOfCookies[i++] = cookie;
727 }
728 return arrayOfCookies;
729 }
730
731 };
732
733 private static final Cookie[] ZERO_COOKIES = new Cookie[0];
734
735
736
737
738
739
740
741 public static CookieStorageType resolveCookieStorageType(Object cookiesObject)
742 {
743 if (cookiesObject == null || cookiesObject instanceof Cookie[])
744 {
745 return CookieStorageType.ARRAY_OF_COOKIES;
746 }
747 else if (cookiesObject instanceof Map)
748 {
749 return CookieStorageType.MAP_STRING_STRING;
750 }
751 else
752 {
753 throw new IllegalArgumentException("Invalid cookiesObject. Only " + Cookie.class + "[] and "
754 + Map.class + " are supported: " + cookiesObject);
755 }
756 }
757
758
759
760
761 public abstract Object putAndMergeCookie(Object preExistentCookies, String cookieName, String cookieValue);
762
763
764
765
766 public abstract Object putAndMergeCookie(Object preExistentCookies, Cookie[] newCookiesArray);
767
768
769
770
771 public abstract Object putAndMergeCookie(Object preExistentCookies, Map<String, String> newCookiesMap);
772
773
774
775
776 public abstract String getCookieValueFromCookies(Object cookiesObject, String cookieName);
777
778
779
780
781
782 public abstract void addCookiesToClient(HttpClient client,
783 Object cookiesObject,
784 String policy,
785 MuleEvent event,
786 URI destinationUri);
787
788
789
790
791 public abstract Cookie[] asArrayOfCookies(Object cookiesObject);
792 }