001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.protocol.http.mock; 018 019import java.io.BufferedReader; 020import java.io.ByteArrayInputStream; 021import java.io.ByteArrayOutputStream; 022import java.io.FileInputStream; 023import java.io.IOException; 024import java.io.InputStreamReader; 025import java.io.OutputStream; 026import java.io.UnsupportedEncodingException; 027import java.nio.charset.Charset; 028import java.security.Principal; 029import java.text.DateFormat; 030import java.text.ParseException; 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.Collection; 034import java.util.Collections; 035import java.util.Date; 036import java.util.Enumeration; 037import java.util.HashMap; 038import java.util.Iterator; 039import java.util.LinkedHashMap; 040import java.util.List; 041import java.util.Locale; 042import java.util.Map; 043 044import javax.servlet.AsyncContext; 045import javax.servlet.DispatcherType; 046import javax.servlet.ReadListener; 047import javax.servlet.RequestDispatcher; 048import javax.servlet.ServletContext; 049import javax.servlet.ServletException; 050import javax.servlet.ServletInputStream; 051import javax.servlet.ServletRequest; 052import javax.servlet.ServletResponse; 053import javax.servlet.http.Cookie; 054import javax.servlet.http.HttpServletRequest; 055import javax.servlet.http.HttpServletResponse; 056import javax.servlet.http.HttpSession; 057import javax.servlet.http.HttpUpgradeHandler; 058import javax.servlet.http.Part; 059 060import org.apache.commons.fileupload.FileUploadBase; 061import org.apache.wicket.Application; 062import org.apache.wicket.WicketRuntimeException; 063import org.apache.wicket.mock.MockRequestParameters; 064import org.apache.wicket.request.Url; 065import org.apache.wicket.request.Url.QueryParameter; 066import org.apache.wicket.util.encoding.UrlDecoder; 067import org.apache.wicket.util.encoding.UrlEncoder; 068import org.apache.wicket.util.file.File; 069import org.apache.wicket.util.io.IOUtils; 070import org.apache.wicket.util.string.StringValue; 071import org.apache.wicket.util.string.Strings; 072import org.apache.wicket.util.value.ValueMap; 073 074 075/** 076 * Mock servlet request. Implements all of the methods from the standard HttpServletRequest class 077 * plus helper methods to aid setting up a request. 078 * 079 * @author Chris Turner 080 */ 081public class MockHttpServletRequest implements HttpServletRequest 082{ 083 /** 084 * A holder class for an uploaded file. 085 * 086 * @author Frank Bille (billen) 087 */ 088 private static class UploadedFile 089 { 090 private File file; 091 private String contentType; 092 093 /** 094 * Construct. 095 * 096 * @param fieldName 097 * @param file 098 * @param contentType 099 */ 100 public UploadedFile(String fieldName, File file, String contentType) 101 { 102 this.file = file; 103 this.contentType = contentType; 104 } 105 106 /** 107 * @return The content type of the file. Mime type. 108 */ 109 public String getContentType() 110 { 111 return contentType; 112 } 113 114 /** 115 * @return The uploaded file. 116 */ 117 public File getFile() 118 { 119 return file; 120 } 121 } 122 123 private final ValueMap attributes = new ValueMap(); 124 125 private String authType; 126 127 private String characterEncoding = "UTF-8"; 128 129 private final ServletContext context; 130 131 private final Map<Cookies.Key, Cookie> cookies = new LinkedHashMap<>(); 132 133 private final ValueMap headers = new ValueMap(); 134 135 private String method; 136 137 private final LinkedHashMap<String, String[]> parameters = new LinkedHashMap<>(); 138 139 private final LinkedHashMap<String, Part> parts = new LinkedHashMap<>(); 140 141 private String path; 142 143 private final HttpSession session; 144 145 private String url; 146 147 private Map<String, List<UploadedFile>> uploadedFiles; 148 149 private boolean useMultiPartContentType; 150 151 private boolean secure = false; 152 153 private String remoteAddr = "127.0.0.1"; 154 155 private String scheme = "http"; 156 157 private String serverName = "localhost"; 158 159 private int serverPort = 80; 160 161 /** 162 * Create the request using the supplied session object. Note that in order for temporary 163 * sessions to work, the supplied session must be an instance of {@link MockHttpSession} 164 * 165 * @param application 166 * The application that this request is for 167 * @param session 168 * The session object 169 * @param context 170 * The current servlet context 171 * @param locale 172 * The current locale 173 */ 174 public MockHttpServletRequest(final Application application, final HttpSession session, 175 final ServletContext context, Locale locale) 176 { 177 this.session = session; 178 this.context = context; 179 initialize(locale); 180 } 181 182 public MockHttpServletRequest(final Application application, final HttpSession session, 183 final ServletContext context) 184 { 185 this(application, session, context, Locale.getDefault()); 186 } 187 188 /** 189 * Add a new cookie. 190 * 191 * @param cookie 192 * The cookie 193 */ 194 public void addCookie(final Cookie cookie) 195 { 196 cookies.put(Cookies.keyOf(cookie), cookie); 197 } 198 199 /** 200 * @param cookies 201 */ 202 public void addCookies(Iterable<Cookie> cookies) 203 { 204 for (Cookie cookie : cookies) 205 { 206 addCookie(cookie); 207 } 208 } 209 210 /** 211 * Add an uploaded file to the request. Use this to simulate a file that has been uploaded to a 212 * field. 213 * 214 * @param fieldName 215 * The fieldname of the upload field. 216 * @param file 217 * The file to upload. 218 * @param contentType 219 * The content type of the file. Must be a correct mimetype. 220 */ 221 public void addFile(String fieldName, File file, String contentType) 222 { 223 if (file != null) { 224 if (file.exists() == false) 225 { 226 throw new IllegalArgumentException( 227 "File does not exists. You must provide an existing file: " 228 + file.getAbsolutePath()); 229 } 230 231 if (file.isFile() == false) 232 { 233 throw new IllegalArgumentException( 234 "You can only add a File, which is not a directory. Only files can be uploaded."); 235 } 236 } 237 238 if (uploadedFiles == null) 239 { 240 uploadedFiles = new HashMap<>(); 241 } 242 243 UploadedFile uf = new UploadedFile(fieldName, file, contentType); 244 245 List<UploadedFile> filesPerField = uploadedFiles.get(fieldName); 246 if (filesPerField == null) 247 { 248 filesPerField = new ArrayList<>(); 249 uploadedFiles.put(fieldName, filesPerField); 250 } 251 252 filesPerField.add(uf); 253 setUseMultiPartContentType(true); 254 } 255 256 /** 257 * Add a header to the request. 258 * 259 * @param name 260 * The name of the header to add 261 * @param value 262 * The value 263 */ 264 public void addHeader(String name, String value) 265 { 266 @SuppressWarnings("unchecked") 267 List<String> list = (List<String>)headers.get(name); 268 if (list == null) 269 { 270 list = new ArrayList<>(1); 271 headers.put(name, list); 272 } 273 list.add(value); 274 } 275 276 /** 277 * Sets a header to the request. Overrides any previous value of this header. 278 * 279 * @param name 280 * The name of the header to add 281 * @param value 282 * The value 283 * @see #addHeader(String, String) 284 */ 285 public void setHeader(String name, String value) 286 { 287 @SuppressWarnings("unchecked") 288 List<String> list = (List<String>)headers.get(name); 289 if (list == null) 290 { 291 list = new ArrayList<>(1); 292 headers.put(name, list); 293 } 294 list.clear(); 295 list.add(value); 296 } 297 298 /** 299 * @param name 300 * @param date 301 */ 302 public void addDateHeader(String name, long date) 303 { 304 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL); 305 String dateString = df.format(new Date(date)); 306 addHeader(name, dateString); 307 } 308 309 /** 310 * Get an attribute. 311 * 312 * @param name 313 * The attribute name 314 * @return The value, or null 315 */ 316 @Override 317 public Object getAttribute(final String name) 318 { 319 return attributes.get(name); 320 } 321 322 /** 323 * Get the names of all of the values. 324 * 325 * @return The names 326 */ 327 @Override 328 public Enumeration<String> getAttributeNames() 329 { 330 return Collections.enumeration(attributes.keySet()); 331 } 332 333 // HttpServletRequest methods 334 335 /** 336 * Get the auth type. 337 * 338 * @return The auth type 339 */ 340 @Override 341 public String getAuthType() 342 { 343 return authType; 344 } 345 346 /** 347 * Get the current character encoding. 348 * 349 * @return The character encoding 350 */ 351 @Override 352 public String getCharacterEncoding() 353 { 354 return characterEncoding; 355 } 356 357 /** 358 * Get the current character set. 359 * 360 * @return The character set 361 */ 362 public Charset getCharset() 363 { 364 return Charset.forName(characterEncoding); 365 } 366 367 /** 368 * true will force Request generate multiPart ContentType and ContentLength 369 * 370 * @param useMultiPartContentType 371 */ 372 public void setUseMultiPartContentType(boolean useMultiPartContentType) 373 { 374 this.useMultiPartContentType = useMultiPartContentType; 375 } 376 377 378 /** 379 * Return the length of the content. This is always -1 except if useMultiPartContentType set as 380 * true. Then the length will be the length of the generated request. 381 * 382 * @return -1 if useMultiPartContentType is false. Else the length of the generated request. 383 */ 384 @Override 385 public int getContentLength() 386 { 387 if (useMultiPartContentType) 388 { 389 byte[] request = buildRequest(); 390 return request.length; 391 } 392 393 return -1; 394 } 395 396 @Override 397 public long getContentLengthLong() 398 { 399 return getContentLength(); 400 } 401 402 /** 403 * If useMultiPartContentType set as true return the correct content-type. 404 * 405 * @return The correct multipart content-type if useMultiPartContentType is true. Else null. 406 */ 407 @Override 408 public String getContentType() 409 { 410 if (useMultiPartContentType) 411 { 412 return FileUploadBase.MULTIPART_FORM_DATA + "; boundary=abcdefgABCDEFG"; 413 } 414 415 return null; 416 } 417 418 /** 419 * Get the context path. For this mock implementation the name of the application is always 420 * returned. 421 * 422 * @return The context path 423 */ 424 @Override 425 public String getContextPath() 426 { 427 // return "/" + application.getName(); 428 return "/context"; 429 } 430 431 /** 432 * @param name 433 * @return Cookie 434 */ 435 public Cookie getCookie(String name) 436 { 437 Cookie[] cookies = getCookies(); 438 if (cookies == null) 439 { 440 return null; 441 } 442 for (Cookie cookie : cookies) 443 { 444 if (cookie.getName().equals(name)) 445 { 446 return Cookies.copyOf(cookie); 447 } 448 } 449 return null; 450 } 451 452 /** 453 * Get all of the cookies for this request. 454 * 455 * @return The cookies 456 */ 457 @Override 458 public Cookie[] getCookies() 459 { 460 if (cookies.isEmpty()) 461 { 462 return null; 463 } 464 List<Cookie> cookieValues = new ArrayList<Cookie>(); 465 cookieValues.addAll(cookies.values()); 466 return cookieValues.toArray(new Cookie[cookieValues.size()]); 467 } 468 469 /** 470 * Get the given header as a date. 471 * 472 * @param name 473 * The header name 474 * @return The date, or -1 if header not found 475 * @throws IllegalArgumentException 476 * If the header cannot be converted 477 */ 478 @Override 479 public long getDateHeader(final String name) throws IllegalArgumentException 480 { 481 String value = getHeader(name); 482 if (value == null) 483 { 484 return -1; 485 } 486 487 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL); 488 try 489 { 490 return df.parse(value).getTime(); 491 } 492 catch (ParseException e) 493 { 494 throw new IllegalArgumentException("Can't convert header to date " + name + ": " 495 + value); 496 } 497 } 498 499 /** 500 * Get the given header value. 501 * 502 * @param name 503 * The header name 504 * @return The header value or null 505 */ 506 @Override 507 public String getHeader(final String name) 508 { 509 @SuppressWarnings("unchecked") 510 final List<String> l = (List<String>)headers.get(name); 511 if (l == null || l.size() < 1) 512 { 513 return null; 514 } 515 else 516 { 517 return l.get(0); 518 } 519 } 520 521 /** 522 * Get the names of all of the headers. 523 * 524 * @return The header names 525 */ 526 @Override 527 public Enumeration<String> getHeaderNames() 528 { 529 return Collections.enumeration(headers.keySet()); 530 } 531 532 /** 533 * Get enumeration of all header values with the given name. 534 * 535 * @param name 536 * The name 537 * @return The header values 538 */ 539 @Override 540 public Enumeration<String> getHeaders(final String name) 541 { 542 @SuppressWarnings("unchecked") 543 List<String> list = (List<String>)headers.get(name); 544 if (list == null) 545 { 546 list = new ArrayList<String>(); 547 } 548 return Collections.enumeration(list); 549 } 550 551 /** 552 * Returns an input stream if there has been added some uploaded files. Use 553 * {@link #addFile(String, File, String)} to add some uploaded files. 554 * 555 * @return The input stream 556 * @throws IOException 557 * If an I/O related problem occurs 558 */ 559 @Override 560 public ServletInputStream getInputStream() throws IOException 561 { 562 byte[] request = buildRequest(); 563 564 // Ok lets make an input stream to return 565 final ByteArrayInputStream bais = new ByteArrayInputStream(request); 566 567 return new ServletInputStream() 568 { 569 private boolean isFinished = false; 570 private boolean isReady = true; 571 572 @Override 573 public boolean isFinished() 574 { 575 return isFinished; 576 } 577 578 @Override 579 public boolean isReady() 580 { 581 return isReady; 582 } 583 584 @Override 585 public void setReadListener(ReadListener readListener) 586 { 587 } 588 589 @Override 590 public int read() 591 { 592 isFinished = true; 593 isReady = false; 594 return bais.read(); 595 } 596 }; 597 } 598 599 /** 600 * Get the given header as an int. 601 * 602 * @param name 603 * The header name 604 * @return The header value or -1 if header not found 605 * @throws NumberFormatException 606 * If the header is not formatted correctly 607 */ 608 @Override 609 public int getIntHeader(final String name) 610 { 611 String value = getHeader(name); 612 if (value == null) 613 { 614 return -1; 615 } 616 return Integer.valueOf(value); 617 } 618 619 /** 620 * Get the locale of the request. Attempts to decode the Accept-Language header and if not found 621 * returns the default locale of the JVM. 622 * 623 * @return The locale 624 */ 625 @Override 626 public Locale getLocale() 627 { 628 return getLocales().nextElement(); 629 } 630 631 public void setLocale(Locale locale) { 632 setHeader("Accept-Language", locale.getLanguage() + '-' + locale.getCountry()); 633 } 634 635 /** 636 * 637 * @param value 638 * @return locale 639 */ 640 private Locale getLocale(final String value) 641 { 642 final String[] bits = Strings.split(value, '-'); 643 if (bits.length < 1) 644 { 645 return null; 646 } 647 648 final String language = bits[0].toLowerCase(Locale.ROOT); 649 if (bits.length > 1) 650 { 651 final String country = bits[1].toUpperCase(Locale.ROOT); 652 return new Locale(language, country); 653 } 654 else 655 { 656 return new Locale(language); 657 } 658 } 659 660 /** 661 * Return all the accepted locales. This implementation always returns just one. 662 * 663 * @return The locales 664 */ 665 @Override 666 public Enumeration<Locale> getLocales() 667 { 668 List<Locale> list = new ArrayList<>(); 669 String header = getHeader("Accept-Language"); 670 if (header != null) 671 { 672 int idxOfSemicolon = header.indexOf(';'); 673 if (idxOfSemicolon > -1) { 674 header = header.substring(0 , idxOfSemicolon); 675 } 676 final String[] locales = Strings.split(header, ','); 677 for (String value : locales) 678 { 679 Locale locale = getLocale(value); 680 if (locale != null) 681 { 682 list.add(locale); 683 } 684 } 685 } 686 687 if (list.size() == 0) 688 { 689 list.add(Locale.getDefault()); 690 } 691 692 return Collections.enumeration(list); 693 } 694 695 /** 696 * Get the method. 697 * 698 * @return The method 699 */ 700 @Override 701 public String getMethod() 702 { 703 return method; 704 } 705 706 /** 707 * Get the request parameter with the given name. 708 * 709 * @param name 710 * The parameter name 711 * @return The parameter value, or null 712 */ 713 @Override 714 public String getParameter(final String name) 715 { 716 String[] param = getParameterMap().get(name); 717 if (param == null) 718 { 719 return null; 720 } 721 else 722 { 723 return param[0]; 724 } 725 } 726 727 /** 728 * Get the map of all of the parameters. 729 * 730 * @return The parameters 731 */ 732 @Override 733 public Map<String, String[]> getParameterMap() 734 { 735 Map<String, String[]> params = new HashMap<>(parameters); 736 737 for (String name : post.getParameterNames()) 738 { 739 List<StringValue> values = post.getParameterValues(name); 740 for (StringValue value : values) 741 { 742 String[] present = params.get(name); 743 if (present == null) 744 { 745 params.put(name, new String[] { value.toString() }); 746 } 747 else 748 { 749 String[] newval = new String[present.length + 1]; 750 System.arraycopy(present, 0, newval, 0, present.length); 751 newval[newval.length - 1] = value.toString(); 752 params.put(name, newval); 753 } 754 } 755 } 756 757 return params; 758 } 759 760 /** 761 * Get the names of all of the parameters. 762 * 763 * @return The parameter names 764 */ 765 @Override 766 public Enumeration<String> getParameterNames() 767 { 768 return Collections.enumeration(getParameterMap().keySet()); 769 } 770 771 /** 772 * Get the values for the given parameter. 773 * 774 * @param name 775 * The name of the parameter 776 * @return The return values 777 */ 778 @Override 779 public String[] getParameterValues(final String name) 780 { 781 Object value = getParameterMap().get(name); 782 if (value == null) 783 { 784 return new String[0]; 785 } 786 787 if (value instanceof String[]) 788 { 789 return (String[])value; 790 } 791 else 792 { 793 String[] result = new String[1]; 794 result[0] = value.toString(); 795 return result; 796 } 797 } 798 799 /** 800 * Get the path info. 801 * 802 * @return The path info 803 */ 804 @Override 805 public String getPathInfo() 806 { 807 return path; 808 } 809 810 /** 811 * Always returns null. 812 * 813 * @return null 814 */ 815 @Override 816 public String getPathTranslated() 817 { 818 return null; 819 } 820 821 /** 822 * Get the protocol. 823 * 824 * @return Always HTTP/1.1 825 */ 826 @Override 827 public String getProtocol() 828 { 829 return "HTTP/1.1"; 830 } 831 832 /** 833 * Get the query string part of the request. 834 * 835 * @return The query string 836 */ 837 @Override 838 public String getQueryString() 839 { 840 if (parameters.size() == 0) 841 { 842 return null; 843 } 844 else 845 { 846 final StringBuilder buf = new StringBuilder(); 847 for (Iterator<String> iterator = parameters.keySet().iterator(); iterator.hasNext();) 848 { 849 final String name = iterator.next(); 850 final String[] values = getParameterValues(name); 851 for (int i = 0; i < values.length; i++) 852 { 853 if (name != null) 854 { 855 buf.append(UrlEncoder.QUERY_INSTANCE.encode(name, getCharset())); 856 } 857 buf.append('='); 858 if (values[i] != null) 859 { 860 buf.append(UrlEncoder.QUERY_INSTANCE.encode(values[i], getCharset())); 861 } 862 if (i + 1 < values.length) 863 { 864 buf.append('&'); 865 } 866 } 867 if (iterator.hasNext()) 868 { 869 buf.append('&'); 870 } 871 } 872 return buf.toString(); 873 } 874 } 875 876 /** 877 * This feature is not implemented at this time as we are not supporting binary servlet input. 878 * This functionality may be added in the future. 879 * 880 * @return The reader 881 * @throws IOException 882 * If an I/O related problem occurs 883 */ 884 @Override 885 public BufferedReader getReader() throws IOException 886 { 887 return new BufferedReader(new InputStreamReader(getInputStream())); 888 } 889 890 /** 891 * Deprecated method - should not be used. 892 * 893 * @param name 894 * The name 895 * @return The path 896 * @deprecated Use ServletContext.getRealPath(String) instead. 897 */ 898 @Override 899 @Deprecated 900 public String getRealPath(String name) 901 { 902 return context.getRealPath(name); 903 } 904 905 /** 906 * @return the remote address of the client 907 */ 908 @Override 909 public String getRemoteAddr() 910 { 911 return remoteAddr; 912 } 913 914 /** 915 * 916 * @param addr 917 * Format: "aaa.bbb.ccc.ddd" 918 */ 919 public void setRemoteAddr(String addr) 920 { 921 remoteAddr = addr; 922 } 923 924 /** 925 * Get the remote host. 926 * 927 * @return Return 'localhost' by default 928 */ 929 @Override 930 public String getRemoteHost() 931 { 932 return "localhost"; 933 } 934 935 /** 936 * Get the name of the remote user from the REMOTE_USER header. 937 * 938 * @return The name of the remote user 939 */ 940 @Override 941 public String getRemoteUser() 942 { 943 return getHeader("REMOTE_USER"); 944 } 945 946 /** 947 * Return a dummy dispatcher that just records that dispatch has occurred without actually doing 948 * anything. 949 * 950 * @param name 951 * The name to dispatch to 952 * @return The dispatcher 953 */ 954 @Override 955 public RequestDispatcher getRequestDispatcher(String name) 956 { 957 return context.getRequestDispatcher(name); 958 } 959 960 /** 961 * Get the requested session id. Always returns the id of the current session. 962 * 963 * @return The session id 964 */ 965 @Override 966 public String getRequestedSessionId() 967 { 968 if (session instanceof MockHttpSession && ((MockHttpSession)session).isTemporary()) 969 { 970 return null; 971 } 972 return session.getId(); 973 } 974 975 /** 976 * Returns context path and servlet path concatenated, typically 977 * /applicationClassName/applicationClassName 978 * 979 * @return The path value 980 * @see javax.servlet.http.HttpServletRequest#getRequestURI() 981 */ 982 @Override 983 public String getRequestURI() 984 { 985 if (url == null) 986 { 987 return getContextPath() + getServletPath(); 988 } 989 else 990 { 991 int index = url.indexOf("?"); 992 if (index != -1) 993 { 994 return url.substring(0, index); 995 } 996 } 997 return url; 998 } 999 1000 /** 1001 * Try to build a rough URL. 1002 * 1003 * @return The url 1004 * @see javax.servlet.http.HttpServletRequest#getRequestURL() 1005 */ 1006 @Override 1007 public StringBuffer getRequestURL() 1008 { 1009 StringBuffer buf = new StringBuffer(); 1010 buf.append("http://localhost"); 1011 buf.append(getContextPath()); 1012 if (getPathInfo() != null) 1013 { 1014 buf.append(getPathInfo()); 1015 } 1016 1017 // No query parameter. See 1018 // http://download.oracle.com/javaee/5/api/javax/servlet/http/HttpServletRequest.html#getRequestURL() 1019 return buf; 1020 } 1021 1022 /** 1023 * Get the scheme. 1024 * 1025 * @return the scheme of this request 1026 */ 1027 @Override 1028 public String getScheme() 1029 { 1030 return scheme; 1031 } 1032 1033 /** 1034 * Sets the scheme of this request 1035 * <p/> 1036 * set the <code>secure</code> flag accordingly (<code>true</code> for 'https', 1037 * <code>false</code> otherwise) 1038 * 1039 * @param scheme 1040 * protocol scheme (e.g. https, http, ftp) 1041 * 1042 * @see #isSecure() 1043 */ 1044 public void setScheme(String scheme) 1045 { 1046 this.scheme = scheme; 1047 secure = "https".equalsIgnoreCase(scheme); 1048 } 1049 1050 /** 1051 * Get the server name. 1052 * 1053 * @return by default returns 'localhost' 1054 */ 1055 @Override 1056 public String getServerName() 1057 { 1058 return serverName; 1059 } 1060 1061 /** 1062 * Set the server name. 1063 * 1064 * @param serverName 1065 * content of 'Host' header 1066 */ 1067 public void setServerName(final String serverName) 1068 { 1069 this.serverName = serverName; 1070 } 1071 1072 /** 1073 * @return the server port of this request 1074 */ 1075 @Override 1076 public int getServerPort() 1077 { 1078 return serverPort; 1079 } 1080 1081 /** 1082 * Sets the server port for this request 1083 * 1084 * @param port 1085 */ 1086 public void setServerPort(int port) 1087 { 1088 serverPort = port; 1089 } 1090 1091 /** 1092 * The servlet path may either be the application name or /. For test purposes we always return 1093 * the servlet name. 1094 * 1095 * @return The servlet path 1096 */ 1097 @Override 1098 public String getServletPath() 1099 { 1100 return "/servlet"; 1101 } 1102 1103 /** 1104 * Get the sessions. 1105 * 1106 * @return The session 1107 */ 1108 @Override 1109 public HttpSession getSession() 1110 { 1111 return getSession(true); 1112 } 1113 1114 @Override 1115 public String changeSessionId() 1116 { 1117 final HttpSession oldSession = getSession(false); 1118 if (oldSession == null) 1119 { 1120 throw new IllegalStateException("There is no active session associated with the current request"); 1121 } 1122 oldSession.invalidate(); 1123 1124 final HttpSession newSession = getSession(true); 1125 1126 return newSession.getId(); 1127 } 1128 1129 /** 1130 * Get the session. 1131 * 1132 * @param createNew 1133 * Ignored, there is always a session 1134 * @return The session 1135 */ 1136 @Override 1137 public HttpSession getSession(boolean createNew) 1138 { 1139 HttpSession sess = null; 1140 if (session instanceof MockHttpSession) 1141 { 1142 MockHttpSession mockHttpSession = (MockHttpSession)session; 1143 if (createNew) 1144 { 1145 mockHttpSession.setTemporary(false); 1146 } 1147 1148 if (mockHttpSession.isTemporary() == false) 1149 { 1150 sess = session; 1151 } 1152 } 1153 return sess; 1154 } 1155 1156 /** 1157 * Get the user principal. 1158 * 1159 * @return A user principal 1160 */ 1161 @Override 1162 public Principal getUserPrincipal() 1163 { 1164 final String user = getRemoteUser(); 1165 if (user == null) 1166 { 1167 return null; 1168 } 1169 else 1170 { 1171 return new Principal() 1172 { 1173 @Override 1174 public String getName() 1175 { 1176 return user; 1177 } 1178 }; 1179 } 1180 } 1181 1182 /** 1183 * @return True if there has been added files to this request using 1184 * {@link #addFile(String, File, String)} 1185 */ 1186 public boolean hasUploadedFiles() 1187 { 1188 return uploadedFiles != null; 1189 } 1190 1191 /** 1192 * Reset the request back to a default state. 1193 * @param locale 1194 */ 1195 public void initialize(Locale locale) 1196 { 1197 authType = null; 1198 method = "post"; 1199 cookies.clear(); 1200 setDefaultHeaders(locale); 1201 path = null; 1202 url = null; 1203 characterEncoding = "UTF-8"; 1204 parameters.clear(); 1205 attributes.clear(); 1206 post.reset(); 1207 } 1208 1209 /** 1210 * Check whether session id is from a cookie. Always returns true. 1211 * 1212 * @return Always true 1213 */ 1214 @Override 1215 public boolean isRequestedSessionIdFromCookie() 1216 { 1217 return true; 1218 } 1219 1220 /** 1221 * Check whether session id is from a url rewrite. Always returns false. 1222 * 1223 * @return Always false 1224 */ 1225 @Override 1226 public boolean isRequestedSessionIdFromUrl() 1227 { 1228 return false; 1229 } 1230 1231 @Override 1232 public boolean authenticate(HttpServletResponse response) throws IOException, ServletException 1233 { 1234 return false; 1235 } 1236 1237 @Override 1238 public void login(String username, String password) throws ServletException 1239 { 1240 } 1241 1242 @Override 1243 public void logout() throws ServletException 1244 { 1245 } 1246 1247 @Override 1248 public Collection<Part> getParts() throws IOException, ServletException 1249 { 1250 return parts.values(); 1251 } 1252 1253 @Override 1254 public Part getPart(String name) throws IOException, ServletException 1255 { 1256 return parts.get(name); 1257 } 1258 1259 @Override 1260 public <T extends HttpUpgradeHandler> T upgrade(Class<T> aClass) throws IOException, ServletException 1261 { 1262 return null; 1263 } 1264 1265 public MockHttpServletRequest setPart(String name, Part part) { 1266 parts.put(name, part); 1267 return this; 1268 } 1269 1270 /** 1271 * Check whether session id is from a url rewrite. Always returns false. 1272 * 1273 * @return Always false 1274 */ 1275 @Override 1276 public boolean isRequestedSessionIdFromURL() 1277 { 1278 return false; 1279 } 1280 1281 /** 1282 * Check whether the session id is valid. 1283 * 1284 * @return Always true 1285 */ 1286 @Override 1287 public boolean isRequestedSessionIdValid() 1288 { 1289 return true; 1290 } 1291 1292 /** 1293 * @return <code>true</code> if this request's scheme is 'https', <code>false</code> - otherwise 1294 */ 1295 @Override 1296 public boolean isSecure() 1297 { 1298 return secure; 1299 } 1300 1301 /** 1302 * 1303 * @param secure 1304 */ 1305 public void setSecure(boolean secure) 1306 { 1307 this.secure = secure; 1308 } 1309 1310 /** 1311 * NOT IMPLEMENTED. 1312 * 1313 * @param name 1314 * The role name 1315 * @return Always false 1316 */ 1317 @Override 1318 public boolean isUserInRole(String name) 1319 { 1320 return false; 1321 } 1322 1323 /** 1324 * Remove the given attribute. 1325 * 1326 * @param name 1327 * The name of the attribute 1328 */ 1329 @Override 1330 public void removeAttribute(final String name) 1331 { 1332 attributes.remove(name); 1333 } 1334 1335 /** 1336 * Set the given attribute. 1337 * 1338 * @param name 1339 * The attribute name 1340 * @param o 1341 * The value to set 1342 */ 1343 @Override 1344 public void setAttribute(final String name, final Object o) 1345 { 1346 attributes.put(name, o); 1347 } 1348 1349 /** 1350 * Set the auth type. 1351 * 1352 * @param authType 1353 * The auth type 1354 */ 1355 public void setAuthType(final String authType) 1356 { 1357 this.authType = authType; 1358 } 1359 1360 /** 1361 * Set the character encoding. 1362 * 1363 * @param encoding 1364 * The character encoding 1365 * @throws UnsupportedEncodingException 1366 * If encoding not supported 1367 */ 1368 @Override 1369 public void setCharacterEncoding(final String encoding) throws UnsupportedEncodingException 1370 { 1371 characterEncoding = encoding; 1372 } 1373 1374 /** 1375 * Set the cookies. 1376 * 1377 * @param theCookies 1378 * The cookies 1379 */ 1380 public void setCookies(final Cookie[] theCookies) 1381 { 1382 cookies.clear(); 1383 addCookies(Arrays.asList(theCookies)); 1384 } 1385 1386 /** 1387 * Set the method. 1388 * 1389 * @param method 1390 * The method 1391 */ 1392 public void setMethod(final String method) 1393 { 1394 this.method = method; 1395 } 1396 1397 /** 1398 * Set a parameter. 1399 * 1400 * @param name 1401 * The name 1402 * @param value 1403 * The value 1404 */ 1405 public void setParameter(final String name, final String value) 1406 { 1407 if (value == null) 1408 { 1409 parameters.remove(name); 1410 } 1411 else 1412 { 1413 parameters.put(name, new String[] { value }); 1414 } 1415 } 1416 1417 /** 1418 * @param name 1419 * @param value 1420 */ 1421 public void addParameter(final String name, final String value) 1422 { 1423 if (value == null) 1424 { 1425 return; 1426 } 1427 String[] val = parameters.get(name); 1428 if (val == null) 1429 { 1430 parameters.put(name, new String[] { value }); 1431 } 1432 else 1433 { 1434 String[] newval = new String[val.length + 1]; 1435 System.arraycopy(val, 0, newval, 0, val.length); 1436 newval[val.length] = value; 1437 parameters.put(name, newval); 1438 } 1439 } 1440 1441 /** 1442 * Sets a map of parameters. 1443 * 1444 * @param parameters 1445 * the parameters to set 1446 */ 1447 public void setParameters(final Map<String, String[]> parameters) 1448 { 1449 this.parameters.putAll(parameters); 1450 } 1451 1452 /** 1453 * Set the path that this request is supposed to be serving. The path is relative to the web 1454 * application root and should start with a / character 1455 * 1456 * @param path 1457 */ 1458 public void setPath(final String path) 1459 { 1460 this.path = UrlDecoder.PATH_INSTANCE.decode(path, getCharset()); 1461 } 1462 1463 /** 1464 * Set the complete url for this request. The url will be analyzed. 1465 * 1466 * @param url 1467 */ 1468 public void setURL(String url) 1469 { 1470 setUrl(Url.parse(url)); 1471 } 1472 1473 /** 1474 * Helper method to create some default headers for the request 1475 * @param l 1476 */ 1477 private void setDefaultHeaders(Locale l) 1478 { 1479 headers.clear(); 1480 addHeader("Accept", "text/xml,application/xml,application/xhtml+xml," 1481 + "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); 1482 addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); 1483 addHeader("Accept-Language", l.getLanguage().toLowerCase(Locale.ROOT) + "-" 1484 + l.getCountry().toLowerCase(Locale.ROOT) + "," + l.getLanguage().toLowerCase(Locale.ROOT) + ";q=0.5"); 1485 addHeader("User-Agent", 1486 "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0"); 1487 } 1488 1489 private static final String crlf = "\r\n"; 1490 private static final String boundary = "--abcdefgABCDEFG"; 1491 1492 private void newAttachment(OutputStream out) throws IOException 1493 { 1494 out.write(boundary.getBytes()); 1495 out.write(crlf.getBytes()); 1496 out.write("Content-Disposition: form-data".getBytes()); 1497 } 1498 1499 /** 1500 * Build the request based on the uploaded files and the parameters. 1501 * 1502 * @return The request as a string. 1503 */ 1504 private byte[] buildRequest() 1505 { 1506 if (uploadedFiles == null && useMultiPartContentType == false) 1507 { 1508 if (post.getParameterNames().size() == 0) 1509 { 1510 return "".getBytes(); 1511 } 1512 Url url = new Url(); 1513 for (final String parameterName : post.getParameterNames()) 1514 { 1515 List<StringValue> values = post.getParameterValues(parameterName); 1516 for (StringValue value : values) 1517 { 1518 url.addQueryParameter(parameterName, value.toString()); 1519 } 1520 } 1521 String body = url.toString().substring(1); 1522 return body.getBytes(); 1523 } 1524 1525 1526 try 1527 { 1528 // Build up the input stream based on the files and parameters 1529 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1530 1531 // Add parameters 1532 for (final String parameterName : post.getParameterNames()) 1533 { 1534 List<StringValue> values = post.getParameterValues(parameterName); 1535 for (StringValue value : values) 1536 { 1537 newAttachment(out); 1538 out.write("; name=\"".getBytes()); 1539 out.write(parameterName.getBytes()); 1540 out.write("\"".getBytes()); 1541 out.write(crlf.getBytes()); 1542 out.write(crlf.getBytes()); 1543 out.write(value.toString().getBytes()); 1544 out.write(crlf.getBytes()); 1545 } 1546 } 1547 1548 // Add files 1549 if (uploadedFiles != null) 1550 { 1551 for (Map.Entry<String, List<UploadedFile>> entry : uploadedFiles.entrySet()) 1552 { 1553 String fieldName = entry.getKey(); 1554 List<UploadedFile> files = entry.getValue(); 1555 1556 for (UploadedFile uf : files) 1557 { 1558 newAttachment(out); 1559 out.write("; name=\"".getBytes()); 1560 out.write(fieldName.getBytes()); 1561 out.write("\"; filename=\"".getBytes()); 1562 if (uf.getFile() != null) { 1563 out.write(uf.getFile().getName().getBytes()); 1564 } 1565 out.write("\"".getBytes()); 1566 out.write(crlf.getBytes()); 1567 out.write("Content-Type: ".getBytes()); 1568 out.write(uf.getContentType().getBytes()); 1569 out.write(crlf.getBytes()); 1570 out.write(crlf.getBytes()); 1571 1572 if (uf.getFile() != null) { 1573 // Load the file and put it into the the inputstream 1574 FileInputStream fis = new FileInputStream(uf.getFile()); 1575 1576 try 1577 { 1578 IOUtils.copy(fis, out); 1579 } 1580 finally 1581 { 1582 fis.close(); 1583 } 1584 } 1585 out.write(crlf.getBytes()); 1586 } 1587 } 1588 } 1589 1590 out.write(boundary.getBytes()); 1591 out.write("--".getBytes()); 1592 out.write(crlf.getBytes()); 1593 return out.toByteArray(); 1594 } 1595 catch (IOException e) 1596 { 1597 // NOTE: IllegalStateException(Throwable) only exists since Java 1.5 1598 throw new WicketRuntimeException(e); 1599 } 1600 } 1601 1602 /** 1603 * @return local address 1604 */ 1605 @Override 1606 public String getLocalAddr() 1607 { 1608 return "127.0.0.1"; 1609 } 1610 1611 /** 1612 * @return local host name 1613 */ 1614 @Override 1615 public String getLocalName() 1616 { 1617 return "127.0.0.1"; 1618 } 1619 1620 /** 1621 * @return local port 1622 */ 1623 @Override 1624 public int getLocalPort() 1625 { 1626 return 80; 1627 } 1628 1629 /** 1630 * @return remote port 1631 */ 1632 @Override 1633 public int getRemotePort() 1634 { 1635 return 80; 1636 } 1637 1638 /** 1639 * @param url 1640 */ 1641 public void setUrl(Url url) 1642 { 1643 if (url.getProtocol() != null) 1644 { 1645 setScheme(url.getProtocol()); 1646 } 1647 if (url.getHost() != null) 1648 { 1649 serverName = url.getHost(); 1650 } 1651 if (url.getPort() != null) 1652 { 1653 serverPort = url.getPort(); 1654 } 1655 String path = url.getPath(getCharset()); 1656 1657 if (path.startsWith("/") == false) 1658 { 1659 path = getContextPath() + getServletPath() + '/' + path; 1660 } 1661 this.url = path; 1662 1663 if (path.startsWith(getContextPath())) 1664 { 1665 path = path.substring(getContextPath().length()); 1666 } 1667 if (path.startsWith(getServletPath())) 1668 { 1669 path = path.substring(getServletPath().length()); 1670 } 1671 1672 setPath(path); 1673 1674 // 1675 // We can't clear the parameters here because users may have set custom 1676 // parameters in request. An better place to clear they is when tester 1677 // setups the next request cycle 1678 // 1679 // parameters.clear(); 1680 1681 for (QueryParameter parameter : url.getQueryParameters()) 1682 { 1683 addParameter(parameter.getName(), parameter.getValue()); 1684 } 1685 } 1686 1687 /** 1688 * @return request url 1689 */ 1690 public Url getUrl() 1691 { 1692 final String urlString; 1693 final String queryString = getQueryString(); 1694 1695 if (Strings.isEmpty(queryString)) 1696 { 1697 urlString = getRequestURI(); 1698 } 1699 else 1700 { 1701 urlString = getRequestURI() + '?' + queryString; 1702 } 1703 1704 final Url url = Url.parse(urlString, getCharset()); 1705 url.setProtocol(scheme); 1706 url.setHost(serverName); 1707 url.setPort(serverPort); 1708 return url; 1709 } 1710 1711 /** 1712 * @return post parameters 1713 */ 1714 public MockRequestParameters getPostParameters() 1715 { 1716 return post; 1717 } 1718 1719 /** 1720 * @return filter prefix 1721 */ 1722 public String getFilterPrefix() 1723 { 1724 return getServletPath().substring(1); 1725 } 1726 1727 private final MockRequestParameters post = new MockRequestParameters(); 1728 1729 /** 1730 * @return ServletContext 1731 */ 1732 @Override 1733 public ServletContext getServletContext() 1734 { 1735 return context; 1736 } 1737 1738 @Override 1739 public AsyncContext startAsync() throws IllegalStateException 1740 { 1741 return null; 1742 } 1743 1744 @Override 1745 public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) 1746 throws IllegalStateException 1747 { 1748 return null; 1749 } 1750 1751 @Override 1752 public boolean isAsyncStarted() 1753 { 1754 return false; 1755 } 1756 1757 @Override 1758 public boolean isAsyncSupported() 1759 { 1760 return false; 1761 } 1762 1763 @Override 1764 public AsyncContext getAsyncContext() 1765 { 1766 return null; 1767 } 1768 1769 @Override 1770 public DispatcherType getDispatcherType() 1771 { 1772 return null; 1773 } 1774 1775}