001package org.apache.maven.wagon.http; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.maven.wagon.FileTestUtils; 023import org.apache.maven.wagon.ResourceDoesNotExistException; 024import org.apache.maven.wagon.StreamingWagon; 025import org.apache.maven.wagon.StreamingWagonTestCase; 026import org.apache.maven.wagon.TransferFailedException; 027import org.apache.maven.wagon.Wagon; 028import org.apache.maven.wagon.authentication.AuthenticationInfo; 029import org.apache.maven.wagon.authorization.AuthorizationException; 030import org.apache.maven.wagon.proxy.ProxyInfo; 031import org.apache.maven.wagon.proxy.ProxyInfoProvider; 032import org.apache.maven.wagon.repository.Repository; 033import org.apache.maven.wagon.resource.Resource; 034import org.codehaus.plexus.util.FileUtils; 035import org.codehaus.plexus.util.IOUtil; 036import org.codehaus.plexus.util.StringUtils; 037import org.eclipse.jetty.security.ConstraintMapping; 038import org.eclipse.jetty.security.ConstraintSecurityHandler; 039import org.eclipse.jetty.security.HashLoginService; 040import org.eclipse.jetty.security.SecurityHandler; 041import org.eclipse.jetty.security.authentication.BasicAuthenticator; 042import org.eclipse.jetty.server.Connector; 043import org.eclipse.jetty.server.HttpConfiguration; 044import org.eclipse.jetty.server.HttpConnectionFactory; 045import org.eclipse.jetty.server.Request; 046import org.eclipse.jetty.server.Response; 047import org.eclipse.jetty.server.Server; 048import org.eclipse.jetty.server.ServerConnector; 049import org.eclipse.jetty.server.handler.AbstractHandler; 050import org.eclipse.jetty.server.handler.HandlerCollection; 051import org.eclipse.jetty.servlet.DefaultServlet; 052import org.eclipse.jetty.servlet.ServletContextHandler; 053import org.eclipse.jetty.servlet.ServletHolder; 054import org.eclipse.jetty.util.security.Constraint; 055import org.eclipse.jetty.util.security.Password; 056 057import javax.servlet.ServletException; 058import javax.servlet.http.HttpServletRequest; 059import javax.servlet.http.HttpServletResponse; 060import java.io.ByteArrayOutputStream; 061import java.io.File; 062import java.io.FileInputStream; 063import java.io.FileOutputStream; 064import java.io.IOException; 065import java.io.InputStream; 066import java.io.OutputStream; 067import java.lang.reflect.Method; 068import java.net.URLDecoder; 069import java.util.ArrayList; 070import java.util.Collections; 071import java.util.Enumeration; 072import java.util.HashMap; 073import java.util.List; 074import java.util.Map; 075import java.util.Properties; 076import java.util.concurrent.atomic.AtomicBoolean; 077import java.util.zip.DeflaterOutputStream; 078import java.util.zip.GZIPOutputStream; 079 080/** 081 * 082 */ 083public abstract class HttpWagonTestCase 084 extends StreamingWagonTestCase 085{ 086 public static final int SC_TOO_MANY_REQUESTS = 429; 087 088 private Server server; 089 private ServerConnector connector; 090 091 protected int getLocalPort( Server server ) 092 { 093 Connector connector = server.getConnectors()[0]; 094 return ( ( ServerConnector ) connector ).getLocalPort(); 095 } 096 097 protected void setupWagonTestingFixtures() 098 throws Exception 099 { 100 // File round trip testing 101 102 File file = FileTestUtils.createUniqueFile( "local-repository", "test-resource" ); 103 104 file.delete(); 105 106 file.getParentFile().mkdirs(); 107 108 File repositoryDirectory = getRepositoryDirectory(); 109 FileUtils.deleteDirectory( repositoryDirectory ); 110 repositoryDirectory.mkdirs(); 111 112 server = new Server( ); 113 //connector = new ServerConnector( server, new HttpConnectionFactory( new HttpConfiguration() ) ); 114 //server.addConnector( connector ); 115 connector = addConnector( server ); 116 117 PutHandler putHandler = new PutHandler( repositoryDirectory ); 118 119 ServletContextHandler context = createContext( server, repositoryDirectory ); 120 HandlerCollection handlers = new HandlerCollection(); 121 handlers.addHandler( putHandler ); 122 handlers.addHandler( context ); 123 server.setHandler( handlers ); 124 125 server.start(); 126 127 testRepository.setUrl( getTestRepositoryUrl() ); 128 } 129 130 @Override 131 protected final int getTestRepositoryPort() 132 { 133 if ( server == null ) 134 { 135 return 0; 136 } 137 return connector.getLocalPort(); 138 } 139 140 protected ServletContextHandler createContext( Server server, File repositoryDirectory ) 141 throws IOException 142 { 143 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS ); 144 root.setResourceBase( repositoryDirectory.getAbsolutePath() ); 145 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); 146 root.addServlet( servletHolder, "/*" ); 147 return root; 148 } 149 150 protected void tearDownWagonTestingFixtures() 151 throws Exception 152 { 153 server.stop(); 154 } 155 156 public void testWagonGetFileList() 157 throws Exception 158 { 159 File dir = getRepositoryDirectory(); 160 FileUtils.deleteDirectory( dir ); 161 162 File f = new File( dir, "file-list" ); 163 f.mkdirs(); 164 165 super.testWagonGetFileList(); 166 } 167 168 public void testHttpHeaders() 169 throws Exception 170 { 171 Properties properties = new Properties(); 172 properties.setProperty( "User-Agent", "Maven-Wagon/1.0" ); 173 174 StreamingWagon wagon = (StreamingWagon) getWagon(); 175 176 setHttpHeaders( wagon, properties ); 177 178 Server server = new Server( ); 179 TestHeaderHandler handler = new TestHeaderHandler(); 180 server.setHandler( handler ); 181 ServerConnector serverConnector = addConnector( server ); 182 server.start(); 183 184 wagon.connect( 185 new Repository( "id", getProtocol() + "://localhost:" + serverConnector.getLocalPort() ) ); 186 187 wagon.getToStream( "resource", new ByteArrayOutputStream() ); 188 189 wagon.disconnect(); 190 191 server.stop(); 192 193 assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) ); 194 } 195 196 /** 197 * test set of User-Agent as it's done by aether wagon connector with using setHttpHeaders 198 */ 199 public void testHttpHeadersWithCommonMethods() 200 throws Exception 201 { 202 Properties properties = new Properties(); 203 properties.setProperty( "User-Agent", "Maven-Wagon/1.0" ); 204 205 StreamingWagon wagon = (StreamingWagon) getWagon(); 206 207 Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class ); 208 setHttpHeaders.invoke( wagon, properties ); 209 210 Server server = new Server( ); 211 ServerConnector serverConnector = addConnector( server ); 212 TestHeaderHandler handler = new TestHeaderHandler(); 213 server.setHandler( handler ); 214 addConnector( server ); 215 server.start(); 216 217 wagon.connect( 218 new Repository( "id", getProtocol() + "://localhost:" + serverConnector.getLocalPort() ) ); 219 220 wagon.getToStream( "resource", new ByteArrayOutputStream() ); 221 222 wagon.disconnect(); 223 224 server.stop(); 225 226 assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) ); 227 } 228 229 public void testUserAgentHeaderIsPresentByDefault() 230 throws Exception 231 { 232 StreamingWagon wagon = (StreamingWagon) getWagon(); 233 Server server = new Server( ); 234 TestHeaderHandler handler = new TestHeaderHandler(); 235 server.setHandler( handler ); 236 addConnector( server ); 237 server.start(); 238 wagon.connect( new Repository( "id", getProtocol() + "://localhost:" + getLocalPort( server ) ) ); 239 wagon.getToStream( "resource", new ByteArrayOutputStream() ); 240 wagon.disconnect(); 241 server.stop(); 242 243 assertNotNull( "default User-Agent header of wagon provider should be present", 244 handler.headers.get( "User-Agent" ) ); 245 } 246 247 public void testUserAgentHeaderIsPresentOnlyOnceIfSetMultipleTimes() 248 throws Exception 249 { 250 StreamingWagon wagon = (StreamingWagon) getWagon(); 251 252 // 1. set User-Agent header via HttpConfiguration 253 Properties headers1 = new Properties(); 254 headers1.setProperty( "User-Agent", "test-user-agent" ); 255 setHttpHeaders( wagon, headers1 ); 256 257 // 2. redundantly set User-Agent header via setHttpHeaders() 258 Properties headers2 = new Properties(); 259 headers2.setProperty( "User-Agent", "test-user-agent" ); 260 Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class ); 261 setHttpHeaders.invoke( wagon, headers2 ); 262 263 Server server = new Server( ); 264 TestHeaderHandler handler = new TestHeaderHandler(); 265 server.setHandler( handler ); 266 addConnector( server ); 267 server.start(); 268 wagon.connect( new Repository( "id", getProtocol() + "://localhost:" + getLocalPort( server ) ) ); 269 wagon.getToStream( "resource", new ByteArrayOutputStream() ); 270 wagon.disconnect(); 271 server.stop(); 272 273 assertEquals( "test-user-agent", handler.headers.get( "User-Agent" ) ); 274 275 } 276 277 protected abstract void setHttpHeaders( StreamingWagon wagon, Properties properties ); 278 279 protected ServerConnector addConnector( Server server ) 280 { 281 ServerConnector serverConnector = 282 new ServerConnector( server, new HttpConnectionFactory( new HttpConfiguration() ) ); 283 server.addConnector( serverConnector ); 284 return serverConnector; 285 } 286 287 protected String getRepositoryUrl( Server server ) 288 { 289 int localPort = getLocalPort( server ); 290 return getProtocol() + "://localhost:" + localPort; 291 } 292 293 public void testGetForbidden() 294 throws Exception 295 { 296 try 297 { 298 runTestGet( HttpServletResponse.SC_FORBIDDEN ); 299 fail(); 300 } 301 catch ( AuthorizationException e ) 302 { 303 assertTrue( true ); 304 } 305 } 306 307 public void testGet404() 308 throws Exception 309 { 310 try 311 { 312 runTestGet( HttpServletResponse.SC_NOT_FOUND ); 313 fail(); 314 } 315 catch ( ResourceDoesNotExistException e ) 316 { 317 assertTrue( true ); 318 } 319 } 320 321 public void testList429() 322 throws Exception 323 { 324 StreamingWagon wagon = (StreamingWagon) getWagon(); 325 try 326 { 327 328 Server server = new Server( ); 329 final AtomicBoolean called = new AtomicBoolean(); 330 331 AbstractHandler handler = new AbstractHandler() 332 { 333 public void handle( String target, Request baseRequest, HttpServletRequest request, 334 HttpServletResponse response ) throws IOException, ServletException 335 { 336 if ( called.get() ) 337 { 338 response.setStatus( HttpServletResponse.SC_OK ); 339 baseRequest.setHandled( true ); 340 } 341 else 342 { 343 called.set( true ); 344 response.setStatus( SC_TOO_MANY_REQUESTS ); 345 baseRequest.setHandled( true ); 346 347 } 348 } 349 }; 350 351 server.setHandler( handler ); 352 ServerConnector serverConnector = addConnector( server ); 353 server.start(); 354 355 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); 356 357 try 358 { 359 wagon.getFileList( "resource" ); 360 } 361 finally 362 { 363 wagon.disconnect(); 364 365 server.stop(); 366 } 367 368 } 369 catch ( ResourceDoesNotExistException e ) 370 { 371 assertTrue( true ); 372 } 373 catch ( TransferFailedException e ) 374 { 375 if ( wagon.getClass().getName().contains( "Lightweight" ) ) 376 { 377 //we don't care about lightweight 378 assertTrue( true ); 379 } 380 else 381 { 382 fail(); 383 } 384 385 } 386 } 387 388 public void testGet500() 389 throws Exception 390 { 391 try 392 { 393 runTestGet( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); 394 fail(); 395 } 396 catch ( TransferFailedException e ) 397 { 398 assertTrue( true ); 399 } 400 } 401 402 private void runTestGet( int status ) 403 throws Exception 404 { 405 StreamingWagon wagon = (StreamingWagon) getWagon(); 406 407 Server server = new Server( ); 408 StatusHandler handler = new StatusHandler(); 409 handler.setStatusToReturn( status ); 410 server.setHandler( handler ); 411 addConnector( server ); 412 server.start(); 413 414 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); 415 416 try 417 { 418 wagon.getToStream( "resource", new ByteArrayOutputStream() ); 419 fail(); 420 } 421 finally 422 { 423 wagon.disconnect(); 424 425 server.stop(); 426 } 427 } 428 429 public void testResourceExistsForbidden() 430 throws Exception 431 { 432 try 433 { 434 runTestResourceExists( HttpServletResponse.SC_FORBIDDEN ); 435 fail(); 436 } 437 catch ( AuthorizationException e ) 438 { 439 assertTrue( true ); 440 } 441 } 442 443 public void testResourceExists404() 444 throws Exception 445 { 446 try 447 { 448 assertFalse( runTestResourceExists( HttpServletResponse.SC_NOT_FOUND ) ); 449 } 450 catch ( ResourceDoesNotExistException e ) 451 { 452 assertTrue( true ); 453 } 454 } 455 456 public void testResourceExists500() 457 throws Exception 458 { 459 try 460 { 461 runTestResourceExists( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); 462 fail(); 463 } 464 catch ( TransferFailedException e ) 465 { 466 assertTrue( true ); 467 } 468 } 469 470 public void testResourceExists429() 471 throws Exception 472 { 473 try 474 { 475 476 final AtomicBoolean called = new AtomicBoolean(); 477 478 AbstractHandler handler = new AbstractHandler() 479 { 480 public void handle( String target, Request baseRequest, HttpServletRequest request, 481 HttpServletResponse response ) throws IOException, ServletException 482 { 483 if ( called.get() ) 484 { 485 response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); 486 baseRequest.setHandled( true ); 487 } 488 else 489 { 490 called.set( true ); 491 response.setStatus( SC_TOO_MANY_REQUESTS ); 492 baseRequest.setHandled( true ); 493 } 494 } 495 }; 496 497 StreamingWagon wagon = (StreamingWagon) getWagon(); 498 Server server = new Server( ); 499 server.setHandler( handler ); 500 addConnector( server ); 501 server.start(); 502 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); 503 504 try 505 { 506 wagon.resourceExists( "resource" ); 507 } 508 finally 509 { 510 wagon.disconnect(); 511 512 server.stop(); 513 } 514 515 fail(); 516 } 517 catch ( TransferFailedException e ) 518 { 519 assertTrue( true ); 520 } 521 } 522 523 524 private boolean runTestResourceExists( int status ) 525 throws Exception 526 { 527 StreamingWagon wagon = (StreamingWagon) getWagon(); 528 529 Server server = new Server( ); 530 StatusHandler handler = new StatusHandler(); 531 handler.setStatusToReturn( status ); 532 server.setHandler( handler ); 533 addConnector( server ); 534 server.start(); 535 536 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); 537 538 try 539 { 540 return wagon.resourceExists( "resource" ); 541 } 542 finally 543 { 544 wagon.disconnect(); 545 546 server.stop(); 547 } 548 } 549 550 protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource ) 551 { 552 File file = new File( getRepositoryDirectory(), resource.getName() ); 553 return ( file.lastModified() / 1000 ) * 1000; 554 } 555 556 protected File getRepositoryDirectory() 557 { 558 return getTestFile( "target/test-output/http-repository" ); 559 } 560 561 public void testGzipGet() 562 throws Exception 563 { 564 Server server = new Server( ); 565 566 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 567 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS ); 568 root.setResourceBase( localRepositoryPath ); 569 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); 570 servletHolder.setInitParameter( "gzip", "true" ); 571 root.addServlet( servletHolder, "/*" ); 572 addConnector( server ); 573 server.setHandler( root ); 574 server.start(); 575 576 try 577 { 578 Wagon wagon = getWagon(); 579 580 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 581 582 File sourceFile = new File( localRepositoryPath + "/gzip" ); 583 584 sourceFile.deleteOnExit(); 585 586 String resName = "gzip-res.txt"; 587 String sourceContent = writeTestFile( sourceFile, resName, "gzip" ); 588 589 wagon.connect( testRepository ); 590 591 File destFile = FileTestUtils.createUniqueFile( getName(), getName() ); 592 593 destFile.deleteOnExit(); 594 595 wagon.get( "gzip/" + resName, destFile ); 596 597 wagon.disconnect(); 598 599 String destContent = FileUtils.fileRead( destFile ); 600 601 assertEquals( sourceContent, destContent ); 602 } 603 finally 604 { 605 server.stop(); 606 } 607 } 608 609 /* This test cannot be enabled because we cannot tell GzipFilter to compress with deflate only 610 public void testDeflateGet() 611 throws Exception 612 { 613 Server server = new Server( ); 614 615 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 616 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS ); 617 root.setResourceBase( localRepositoryPath ); 618 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); 619 root.addServlet( servletHolder, "/*" ); 620 FilterHolder filterHolder = new FilterHolder( new GzipFilter() ); 621 root.addFilter( filterHolder, "/deflate/*", EnumSet.of( DispatcherType.REQUEST ) ); 622 addConnector( server ); 623 server.setHandler( root ); 624 server.start(); 625 626 try 627 { 628 Wagon wagon = getWagon(); 629 630 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 631 632 File sourceFile = new File( localRepositoryPath + "/deflate" ); 633 634 sourceFile.deleteOnExit(); 635 636 String resName = "deflate-res.txt"; 637 String sourceContent = writeTestFile( sourceFile, resName, null ); 638 639 wagon.connect( testRepository ); 640 641 File destFile = FileTestUtils.createUniqueFile( getName(), getName() ); 642 643 destFile.deleteOnExit(); 644 645 wagon.get( "deflate/" + resName, destFile ); 646 647 wagon.disconnect(); 648 649 String destContent = FileUtils.fileRead( destFile ); 650 651 assertEquals( sourceContent, destContent ); 652 } 653 finally 654 { 655 server.stop(); 656 } 657 }*/ 658 659 public void testProxiedRequest() 660 throws Exception 661 { 662 ProxyInfo proxyInfo = createProxyInfo(); 663 TestHeaderHandler handler = new TestHeaderHandler(); 664 665 runTestProxiedRequest( proxyInfo, handler ); 666 } 667 668 public void testProxiedRequestWithAuthentication() 669 throws Exception 670 { 671 ProxyInfo proxyInfo = createProxyInfo(); 672 proxyInfo.setUserName( "user" ); 673 proxyInfo.setPassword( "secret" ); 674 AuthorizingProxyHandler handler = new AuthorizingProxyHandler(); 675 676 runTestProxiedRequest( proxyInfo, handler ); 677 678 assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) ); 679 680 if ( supportProxyPreemptiveAuthentication() ) 681 { 682 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 0 ).responseCode ); 683 } 684 else 685 { 686 assertEquals( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED, 687 handler.handlerRequestResponses.get( 0 ).responseCode ); 688 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 1 ).responseCode ); 689 } 690 691 } 692 693 public void testProxiedRequestWithAuthenticationWithProvider() 694 throws Exception 695 { 696 final ProxyInfo proxyInfo = createProxyInfo(); 697 proxyInfo.setUserName( "user" ); 698 proxyInfo.setPassword( "secret" ); 699 AuthorizingProxyHandler handler = new AuthorizingProxyHandler(); 700 701 ProxyInfoProvider proxyInfoProvider = new ProxyInfoProvider() 702 { 703 public ProxyInfo getProxyInfo( String protocol ) 704 { 705 return proxyInfo; 706 } 707 }; 708 runTestProxiedRequestWithProvider( proxyInfoProvider, handler ); 709 710 assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) ); 711 712 if ( supportProxyPreemptiveAuthentication() ) 713 { 714 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 0 ).responseCode ); 715 } 716 else 717 { 718 assertEquals( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED, 719 handler.handlerRequestResponses.get( 0 ).responseCode ); 720 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 1 ).responseCode ); 721 } 722 723 } 724 725 public void testRedirectGetToStream() 726 throws Exception 727 { 728 StreamingWagon wagon = (StreamingWagon) getWagon(); 729 730 Server realServer = new Server( ); 731 TestHeaderHandler handler = new TestHeaderHandler(); 732 733 realServer.setHandler( handler ); 734 addConnector( realServer ); 735 realServer.start(); 736 737 Server redirectServer = new Server( ); 738 739 addConnector( redirectServer ); 740 741 String protocol = getProtocol(); 742 743 // protocol is wagon protocol but in fact dav is http(s) 744 if ( protocol.equals( "dav" ) ) 745 { 746 protocol = "http"; 747 } 748 749 if ( protocol.equals( "davs" ) ) 750 { 751 protocol = "https"; 752 } 753 754 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer ); 755 756 RedirectHandler redirectHandler = 757 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, null ); 758 759 redirectServer.setHandler( redirectHandler ); 760 761 redirectServer.start(); 762 763 wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) ); 764 765 File tmpResult = File.createTempFile( "foo", "get" ); 766 767 try ( FileOutputStream fileOutputStream = new FileOutputStream( tmpResult ) ) 768 { 769 wagon.getToStream( "resource", fileOutputStream ); 770 fileOutputStream.flush(); 771 fileOutputStream.close(); 772 String found = FileUtils.fileRead( tmpResult ); 773 assertEquals( "found:'" + found + "'", "Hello, World!", found ); 774 775 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER ); 776 checkHandlerResult( handler.handlerRequestResponses, HttpServletResponse.SC_OK ); 777 } 778 finally 779 { 780 wagon.disconnect(); 781 782 redirectServer.stop(); 783 realServer.stop(); 784 785 tmpResult.delete(); 786 } 787 } 788 789 public void testRedirectGet() 790 throws Exception 791 { 792 StreamingWagon wagon = (StreamingWagon) getWagon(); 793 794 Server realServer = new Server( ); 795 TestHeaderHandler handler = new TestHeaderHandler(); 796 797 realServer.setHandler( handler ); 798 addConnector( realServer ); 799 realServer.start(); 800 801 Server redirectServer = new Server( ); 802 803 addConnector( redirectServer ); 804 805 String protocol = getProtocol(); 806 807 // protocol is wagon protocol but in fact dav is http(s) 808 if ( protocol.equals( "dav" ) ) 809 { 810 protocol = "http"; 811 } 812 813 if ( protocol.equals( "davs" ) ) 814 { 815 protocol = "https"; 816 } 817 818 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer ); 819 820 RedirectHandler redirectHandler = 821 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, null ); 822 823 redirectServer.setHandler( redirectHandler ); 824 825 redirectServer.start(); 826 827 wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) ); 828 829 File tmpResult = File.createTempFile( "foo", "get" ); 830 831 try 832 { 833 wagon.get( "resource", tmpResult ); 834 String found = FileUtils.fileRead( tmpResult ); 835 assertEquals( "found:'" + found + "'", "Hello, World!", found ); 836 837 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER ); 838 checkHandlerResult( handler.handlerRequestResponses, HttpServletResponse.SC_OK ); 839 } 840 finally 841 { 842 wagon.disconnect(); 843 844 redirectServer.stop(); 845 realServer.stop(); 846 847 tmpResult.delete(); 848 } 849 } 850 851 852 public void testRedirectPutFromStreamWithFullUrl() 853 throws Exception 854 { 855 Server realServer = new Server( ); 856 857 addConnector( realServer ); 858 859 File repositoryDirectory = getRepositoryDirectory(); 860 FileUtils.deleteDirectory( repositoryDirectory ); 861 repositoryDirectory.mkdirs(); 862 863 PutHandler putHandler = new PutHandler( repositoryDirectory ); 864 865 realServer.setHandler( putHandler ); 866 867 realServer.start(); 868 869 Server redirectServer = new Server( ); 870 871 addConnector( redirectServer ); 872 873 String protocol = getProtocol(); 874 875 // protocol is wagon protocol but in fact dav is http(s) 876 if ( protocol.equals( "dav" ) ) 877 { 878 protocol = "http"; 879 } 880 881 if ( protocol.equals( "davs" ) ) 882 { 883 protocol = "https"; 884 } 885 886 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer ); 887 888 RedirectHandler redirectHandler = 889 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, repositoryDirectory ); 890 891 redirectServer.setHandler( redirectHandler ); 892 893 redirectServer.start(); 894 895 try 896 { 897 StreamingWagon wagon = (StreamingWagon) getWagon(); 898 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); 899 wagon.connect( repository ); 900 901 File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" ); 902 sourceFile.delete(); 903 assertFalse( sourceFile.exists() ); 904 905 File tempFile = File.createTempFile( "wagon", "tmp" ); 906 tempFile.deleteOnExit(); 907 String content = "put top secret"; 908 FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); 909 910 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) ) 911 { 912 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 ); 913 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); 914 915 checkRequestResponseForRedirectPutWithFullUrl( redirectHandler, putHandler ); 916 } 917 finally 918 { 919 wagon.disconnect(); 920 tempFile.delete(); 921 } 922 923 } 924 finally 925 { 926 realServer.stop(); 927 redirectServer.stop(); 928 } 929 } 930 931 protected void checkRequestResponseForRedirectPutWithFullUrl( RedirectHandler redirectHandler, 932 PutHandler putHandler ) 933 { 934 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER ); 935 checkHandlerResult( putHandler.handlerRequestResponses, HttpServletResponse.SC_CREATED ); 936 } 937 938 public void testRedirectPutFromStreamRelativeUrl() 939 throws Exception 940 { 941 Server realServer = new Server( ); 942 addConnector( realServer ); 943 File repositoryDirectory = getRepositoryDirectory(); 944 FileUtils.deleteDirectory( repositoryDirectory ); 945 repositoryDirectory.mkdirs(); 946 947 PutHandler putHandler = new PutHandler( repositoryDirectory ); 948 949 realServer.setHandler( putHandler ); 950 951 realServer.start(); 952 953 Server redirectServer = new Server( ); 954 955 addConnector( redirectServer ); 956 957 RedirectHandler redirectHandler = 958 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo", 959 repositoryDirectory ); 960 961 redirectServer.setHandler( redirectHandler ); 962 963 redirectServer.start(); 964 965 try 966 { 967 StreamingWagon wagon = (StreamingWagon) getWagon(); 968 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); 969 wagon.connect( repository ); 970 971 File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" ); 972 sourceFile.delete(); 973 assertFalse( sourceFile.exists() ); 974 975 File tempFile = File.createTempFile( "wagon", "tmp" ); 976 tempFile.deleteOnExit(); 977 String content = "put top secret"; 978 FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); 979 980 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) ) 981 { 982 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 ); 983 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); 984 985 checkRequestResponseForRedirectPutWithRelativeUrl( redirectHandler, putHandler ); 986 } 987 finally 988 { 989 wagon.disconnect(); 990 tempFile.delete(); 991 } 992 993 } 994 finally 995 { 996 realServer.stop(); 997 redirectServer.stop(); 998 } 999 } 1000 1001 protected void checkRequestResponseForRedirectPutWithRelativeUrl( RedirectHandler redirectHandler, 1002 PutHandler putHandler ) 1003 { 1004 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER, 1005 HttpServletResponse.SC_CREATED ); 1006 checkHandlerResult( putHandler.handlerRequestResponses ); 1007 } 1008 1009 protected void checkHandlerResult( List<HandlerRequestResponse> handlerRequestResponses, 1010 int... expectedResponseCodes ) 1011 { 1012 boolean success = true; 1013 if ( handlerRequestResponses.size() == expectedResponseCodes.length ) 1014 { 1015 for ( int i = 0; i < expectedResponseCodes.length; i++ ) 1016 { 1017 success &= ( expectedResponseCodes[i] == handlerRequestResponses.get( i ).responseCode ); 1018 } 1019 } 1020 1021 if ( !success ) 1022 { 1023 fail( "expected " + expectedResponseCodes + ", got " + handlerRequestResponses ); 1024 } 1025 } 1026 1027 public void testRedirectPutFileWithFullUrl() 1028 throws Exception 1029 { 1030 Server realServer = new Server( ); 1031 1032 addConnector( realServer ); 1033 1034 File repositoryDirectory = getRepositoryDirectory(); 1035 FileUtils.deleteDirectory( repositoryDirectory ); 1036 repositoryDirectory.mkdirs(); 1037 1038 PutHandler putHandler = new PutHandler( repositoryDirectory ); 1039 1040 realServer.setHandler( putHandler ); 1041 1042 realServer.start(); 1043 1044 Server redirectServer = new Server( ); 1045 1046 addConnector( redirectServer ); 1047 1048 String protocol = getProtocol(); 1049 1050 // protocol is wagon protocol but in fact dav is http(s) 1051 if ( protocol.equals( "dav" ) ) 1052 { 1053 protocol = "http"; 1054 } 1055 1056 if ( protocol.equals( "davs" ) ) 1057 { 1058 protocol = "https"; 1059 } 1060 1061 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer ); 1062 1063 RedirectHandler redirectHandler = 1064 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, repositoryDirectory ); 1065 1066 redirectServer.setHandler( redirectHandler ); 1067 1068 redirectServer.start(); 1069 1070 try 1071 { 1072 StreamingWagon wagon = (StreamingWagon) getWagon(); 1073 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); 1074 wagon.connect( repository ); 1075 1076 File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" ); 1077 sourceFile.delete(); 1078 assertFalse( sourceFile.exists() ); 1079 1080 File tempFile = File.createTempFile( "wagon", "tmp" ); 1081 tempFile.deleteOnExit(); 1082 String content = "put top secret"; 1083 FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); 1084 1085 try 1086 { 1087 wagon.put( tempFile, "test-secured-put-resource" ); 1088 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); 1089 1090 checkRequestResponseForRedirectPutWithFullUrl( redirectHandler, putHandler ); 1091 } 1092 finally 1093 { 1094 wagon.disconnect(); 1095 tempFile.delete(); 1096 } 1097 1098 } 1099 finally 1100 { 1101 realServer.stop(); 1102 redirectServer.stop(); 1103 } 1104 } 1105 1106 1107 public void testRedirectPutFileRelativeUrl() 1108 throws Exception 1109 { 1110 Server realServer = new Server( ); 1111 addConnector( realServer ); 1112 File repositoryDirectory = getRepositoryDirectory(); 1113 FileUtils.deleteDirectory( repositoryDirectory ); 1114 repositoryDirectory.mkdirs(); 1115 1116 PutHandler putHandler = new PutHandler( repositoryDirectory ); 1117 1118 realServer.setHandler( putHandler ); 1119 1120 realServer.start(); 1121 1122 Server redirectServer = new Server( ); 1123 1124 addConnector( redirectServer ); 1125 1126 RedirectHandler redirectHandler = 1127 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo", 1128 repositoryDirectory ); 1129 1130 redirectServer.setHandler( redirectHandler ); 1131 1132 redirectServer.start(); 1133 1134 try 1135 { 1136 StreamingWagon wagon = (StreamingWagon) getWagon(); 1137 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); 1138 wagon.connect( repository ); 1139 1140 File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" ); 1141 sourceFile.delete(); 1142 assertFalse( sourceFile.exists() ); 1143 1144 File tempFile = File.createTempFile( "wagon", "tmp" ); 1145 tempFile.deleteOnExit(); 1146 String content = "put top secret"; 1147 FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); 1148 1149 try 1150 { 1151 wagon.put( tempFile, "test-secured-put-resource" ); 1152 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); 1153 1154 checkRequestResponseForRedirectPutWithRelativeUrl( redirectHandler, putHandler ); 1155 } 1156 finally 1157 { 1158 wagon.disconnect(); 1159 tempFile.delete(); 1160 } 1161 1162 } 1163 finally 1164 { 1165 realServer.stop(); 1166 redirectServer.stop(); 1167 } 1168 } 1169 1170 1171 /** 1172 * 1173 */ 1174 @SuppressWarnings( "checkstyle:visibilitymodifier" ) 1175 public static class RedirectHandler 1176 extends AbstractHandler 1177 { 1178 String reason; 1179 1180 int retCode; 1181 1182 String redirectUrl; 1183 1184 File repositoryDirectory; 1185 1186 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>(); 1187 1188 RedirectHandler( String reason, int retCode, String redirectUrl, File repositoryDirectory ) 1189 { 1190 this.reason = reason; 1191 this.retCode = retCode; 1192 this.redirectUrl = redirectUrl; 1193 this.repositoryDirectory = repositoryDirectory; 1194 } 1195 1196 public void handle( String target, Request baseRequest, HttpServletRequest request, 1197 HttpServletResponse response ) throws IOException, ServletException 1198 { 1199 if ( request.getRequestURI().contains( "redirectRequest" ) ) 1200 { 1201 PutHandler putHandler = new PutHandler( this.repositoryDirectory ); 1202 putHandler.handle( target, baseRequest, request, response ); 1203 handlerRequestResponses.add( 1204 new HandlerRequestResponse( request.getMethod(), response.getStatus(), 1205 request.getRequestURI() ) ); 1206 return; 1207 } 1208 response.setStatus( this.retCode ); 1209 response.setHeader( "Location", this.redirectUrl + request.getRequestURI() ); 1210 baseRequest.setHandled( true ); 1211 1212 handlerRequestResponses.add( 1213 new HandlerRequestResponse( request.getMethod(), response.getStatus(), 1214 request.getRequestURI() ) ); 1215 } 1216 1217 1218 } 1219 1220 1221 private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler ) 1222 throws Exception 1223 { 1224 // what an UGLY hack! 1225 // but apparently jetty needs some time to free up resources 1226 // <5s: broken test :( 1227 // CHECKSTYLE_OFF: MagicNumber 1228 Thread.sleep( 5001L ); 1229 // CHECKSTYLE_ON: MagicNumber 1230 1231 Server proxyServer = new Server( ); 1232 ServerConnector serverConnector = 1233 new ServerConnector( proxyServer, new HttpConnectionFactory( new HttpConfiguration() ) ); 1234 proxyServer.addConnector( serverConnector ); 1235 proxyServer.setHandler( handler ); 1236 1237 proxyServer.start(); 1238 1239 proxyInfo.setPort( getLocalPort( proxyServer ) ); 1240 1241 System.out.println( 1242 "start proxy on host/port " + proxyInfo.getHost() + "/" + proxyInfo.getPort() + " with non proxyHosts " 1243 + proxyInfo.getNonProxyHosts() ); 1244 1245 while ( !proxyServer.isRunning() || !proxyServer.isStarted() ) 1246 { 1247 Thread.sleep( 10 ); 1248 } 1249 1250 try 1251 { 1252 StreamingWagon wagon = (StreamingWagon) getWagon(); 1253 1254 Repository testRepository = new Repository( "id", "http://www.example.com/" ); 1255 1256 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1257 File sourceFile = new File( localRepositoryPath, "test-proxied-resource" ); 1258 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" ); 1259 1260 wagon.connect( testRepository, proxyInfo ); 1261 1262 try 1263 { 1264 wagon.getToStream( "test-proxied-resource", new ByteArrayOutputStream() ); 1265 1266 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) ); 1267 } 1268 finally 1269 { 1270 System.setProperty( "http.proxyHost", "" ); 1271 System.setProperty( "http.proxyPort", "" ); 1272 wagon.disconnect(); 1273 } 1274 } 1275 finally 1276 { 1277 proxyServer.stop(); 1278 } 1279 } 1280 1281 private void runTestProxiedRequestWithProvider( ProxyInfoProvider proxyInfoProvider, TestHeaderHandler handler ) 1282 throws Exception 1283 { 1284 // what an UGLY hack! 1285 // but apparently jetty needs some time to free up resources 1286 // <5s: broken test :( 1287 // CHECKSTYLE_OFF: MagicNumber 1288 Thread.sleep( 5001L ); 1289 // CHECKSTYLE_ON: MagicNumber 1290 1291 Server proxyServer = new Server( ); 1292 ServerConnector serverConnector = 1293 new ServerConnector( proxyServer, new HttpConnectionFactory( new HttpConfiguration() ) ); 1294 proxyServer.addConnector( serverConnector ); 1295 1296 proxyServer.setHandler( handler ); 1297 1298 proxyServer.start(); 1299 1300 proxyInfoProvider.getProxyInfo( null ).setPort( getLocalPort( proxyServer ) ); 1301 1302 System.out.println( "start proxy on host/port " + proxyInfoProvider.getProxyInfo( null ).getHost() + "/" 1303 + proxyInfoProvider.getProxyInfo( null ).getPort() + " with non proxyHosts " 1304 + proxyInfoProvider.getProxyInfo( null ).getNonProxyHosts() ); 1305 1306 while ( !proxyServer.isRunning() || !proxyServer.isStarted() ) 1307 { 1308 Thread.sleep( 10 ); 1309 } 1310 1311 try 1312 { 1313 StreamingWagon wagon = (StreamingWagon) getWagon(); 1314 1315 Repository testRepository = new Repository( "id", "http://www.example.com/" ); 1316 1317 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1318 File sourceFile = new File( localRepositoryPath, "test-proxied-resource" ); 1319 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" ); 1320 1321 wagon.connect( testRepository, proxyInfoProvider ); 1322 1323 try 1324 { 1325 wagon.getToStream( "test-proxied-resource", new ByteArrayOutputStream() ); 1326 1327 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) ); 1328 } 1329 finally 1330 { 1331 System.setProperty( "http.proxyHost", "" ); 1332 System.setProperty( "http.proxyPort", "" ); 1333 wagon.disconnect(); 1334 } 1335 } 1336 finally 1337 { 1338 proxyServer.stop(); 1339 } 1340 } 1341 1342 private ProxyInfo createProxyInfo() 1343 { 1344 ProxyInfo proxyInfo = new ProxyInfo(); 1345 proxyInfo.setHost( "localhost" ); 1346 proxyInfo.setNonProxyHosts( null ); 1347 proxyInfo.setType( "http" ); 1348 return proxyInfo; 1349 } 1350 1351 public void testSecuredGetUnauthorized() 1352 throws Exception 1353 { 1354 try 1355 { 1356 runTestSecuredGet( null ); 1357 fail(); 1358 } 1359 catch ( AuthorizationException e ) 1360 { 1361 assertTrue( true ); 1362 } 1363 } 1364 1365 public void testSecuredGetWrongPassword() 1366 throws Exception 1367 { 1368 try 1369 { 1370 AuthenticationInfo authInfo = new AuthenticationInfo(); 1371 authInfo.setUserName( "user" ); 1372 authInfo.setPassword( "admin" ); 1373 runTestSecuredGet( authInfo ); 1374 fail(); 1375 } 1376 catch ( AuthorizationException e ) 1377 { 1378 assertTrue( true ); 1379 } 1380 } 1381 1382 public void testSecuredGet() 1383 throws Exception 1384 { 1385 AuthenticationInfo authInfo = new AuthenticationInfo(); 1386 authInfo.setUserName( "user" ); 1387 authInfo.setPassword( "secret" ); 1388 runTestSecuredGet( authInfo ); 1389 } 1390 1391 1392 public void runTestSecuredGet( AuthenticationInfo authInfo ) 1393 throws Exception 1394 { 1395 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1396 Server server = createSecurityServer( localRepositoryPath ); 1397 1398 server.start(); 1399 1400 try 1401 { 1402 StreamingWagon wagon = (StreamingWagon) getWagon(); 1403 1404 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 1405 1406 File sourceFile = new File( localRepositoryPath, "test-secured-resource" ); 1407 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" ); 1408 1409 wagon.connect( testRepository, authInfo ); 1410 1411 File file = File.createTempFile( "wagon-test", "txt" ); 1412 1413 try 1414 { 1415 wagon.get( "test-secured-resource", file ); 1416 } 1417 finally 1418 { 1419 wagon.disconnect(); 1420 } 1421 1422 FileInputStream in = new FileInputStream( file ); 1423 1424 assertEquals( "top secret", IOUtil.toString( in ) ); 1425 1426 /* 1427 * We need to wait a bit for all Jetty workers/threads to complete their work. Otherwise 1428 * we may suffer from race conditions where handlerRequestResponses list is not completely 1429 * populated and its premature iteration in testPreemptiveAuthenticationGet will lead to 1430 * a test failure. 1431 */ 1432 // CHECKSTYLE_OFF: MagicNumber 1433 Thread.sleep ( 2000L ); 1434 // CHECKSTYLE_ON: MagicNumber 1435 1436 TestSecurityHandler securityHandler = server.getChildHandlerByClass( TestSecurityHandler.class ); 1437 testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() ); 1438 1439 } 1440 finally 1441 { 1442 server.stop(); 1443 } 1444 } 1445 1446 1447 public void testSecuredGetToStream() 1448 throws Exception 1449 { 1450 AuthenticationInfo authInfo = new AuthenticationInfo(); 1451 authInfo.setUserName( "user" ); 1452 authInfo.setPassword( "secret" ); 1453 runTestSecuredGetToStream( authInfo ); 1454 } 1455 1456 public void runTestSecuredGetToStream( AuthenticationInfo authInfo ) 1457 throws Exception 1458 { 1459 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1460 Server server = createSecurityServer( localRepositoryPath ); 1461 1462 server.start(); 1463 1464 try 1465 { 1466 StreamingWagon wagon = (StreamingWagon) getWagon(); 1467 1468 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 1469 1470 File sourceFile = new File( localRepositoryPath, "test-secured-resource" ); 1471 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" ); 1472 1473 wagon.connect( testRepository, authInfo ); 1474 1475 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1476 try 1477 { 1478 wagon.getToStream( "test-secured-resource", out ); 1479 } 1480 finally 1481 { 1482 wagon.disconnect(); 1483 } 1484 1485 assertEquals( "top secret", out.toString( "US-ASCII" ) ); 1486 1487 /* 1488 * We need to wait a bit for all Jetty workers/threads to complete their work. Otherwise 1489 * we may suffer from race conditions where handlerRequestResponses list is not completely 1490 * populated and its premature iteration in testPreemptiveAuthenticationGet will lead to 1491 * a test failure. 1492 */ 1493 // CHECKSTYLE_OFF: MagicNumber 1494 Thread.sleep ( 2000L ); 1495 // CHECKSTYLE_ON: MagicNumber 1496 1497 TestSecurityHandler securityHandler = server.getChildHandlerByClass( TestSecurityHandler.class ); 1498 testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() ); 1499 } 1500 finally 1501 { 1502 server.stop(); 1503 } 1504 } 1505 1506 public void testSecuredResourceExistsUnauthorized() 1507 throws Exception 1508 { 1509 try 1510 { 1511 runTestSecuredResourceExists( null ); 1512 fail(); 1513 } 1514 catch ( AuthorizationException e ) 1515 { 1516 assertTrue( true ); 1517 } 1518 } 1519 1520 public void testSecuredResourceExistsWrongPassword() 1521 throws Exception 1522 { 1523 try 1524 { 1525 AuthenticationInfo authInfo = new AuthenticationInfo(); 1526 authInfo.setUserName( "user" ); 1527 authInfo.setPassword( "admin" ); 1528 runTestSecuredResourceExists( authInfo ); 1529 } 1530 catch ( AuthorizationException e ) 1531 { 1532 assertTrue( true ); 1533 } 1534 } 1535 1536 public void testSecuredResourceExists() 1537 throws Exception 1538 { 1539 AuthenticationInfo authInfo = new AuthenticationInfo(); 1540 authInfo.setUserName( "user" ); 1541 authInfo.setPassword( "secret" ); 1542 runTestSecuredResourceExists( authInfo ); 1543 } 1544 1545 public void runTestSecuredResourceExists( AuthenticationInfo authInfo ) 1546 throws Exception 1547 { 1548 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1549 Server server = createSecurityServer( localRepositoryPath ); 1550 1551 server.start(); 1552 1553 try 1554 { 1555 StreamingWagon wagon = (StreamingWagon) getWagon(); 1556 1557 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 1558 1559 File sourceFile = new File( localRepositoryPath, "test-secured-resource-exists" ); 1560 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" ); 1561 1562 wagon.connect( testRepository, authInfo ); 1563 1564 try 1565 { 1566 assertTrue( wagon.resourceExists( "test-secured-resource-exists" ) ); 1567 1568 assertFalse( wagon.resourceExists( "test-secured-resource-not-exists" ) ); 1569 } 1570 finally 1571 { 1572 wagon.disconnect(); 1573 } 1574 } 1575 finally 1576 { 1577 server.stop(); 1578 } 1579 } 1580 1581 private Server createSecurityServer( String localRepositoryPath ) 1582 { 1583 Server server = new Server( ); 1584 1585 SecurityHandler sh = createSecurityHandler(); 1586 1587 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS 1588 | ServletContextHandler.SECURITY ); 1589 root.setResourceBase( localRepositoryPath ); 1590 root.setSecurityHandler( sh ); 1591 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); 1592 root.addServlet( servletHolder, "/*" ); 1593 1594 server.setHandler( root ); 1595 addConnector( server ); 1596 return server; 1597 } 1598 1599 1600 private String writeTestFile( File parent, String child, String compressionType ) 1601 throws IOException 1602 { 1603 File file = new File( parent, child ); 1604 file.getParentFile().mkdirs(); 1605 file.deleteOnExit(); 1606 OutputStream out = new FileOutputStream( file ); 1607 try 1608 { 1609 out.write( child.getBytes() ); 1610 } 1611 finally 1612 { 1613 out.close(); 1614 } 1615 1616 String ext = ""; 1617 if ( "gzip".equals( compressionType ) ) 1618 { 1619 ext = ".gz"; 1620 } 1621 if ( "deflate".equals( compressionType ) ) 1622 { 1623 ext = ".deflate"; 1624 } 1625 1626 file = new File( parent, child + ext ); 1627 file.deleteOnExit(); 1628 String content; 1629 out = new FileOutputStream( file ); 1630 if ( "gzip".equals( compressionType ) ) 1631 { 1632 out = new GZIPOutputStream( out ); 1633 } 1634 if ( "deflate".equals( compressionType ) ) 1635 { 1636 out = new DeflaterOutputStream( out ); 1637 } 1638 try 1639 { 1640 // write out different data than non-compressed file, so we can 1641 // assert the compressed version was returned 1642 content = file.getAbsolutePath(); 1643 out.write( content.getBytes() ); 1644 } 1645 finally 1646 { 1647 out.close(); 1648 } 1649 1650 return content; 1651 } 1652 1653 public void testPutForbidden() 1654 throws Exception 1655 { 1656 try 1657 { 1658 runTestPut( HttpServletResponse.SC_FORBIDDEN ); 1659 fail(); 1660 } 1661 catch ( AuthorizationException e ) 1662 { 1663 assertTrue( true ); 1664 } 1665 } 1666 1667 public void testPut404() 1668 throws Exception 1669 { 1670 try 1671 { 1672 runTestPut( HttpServletResponse.SC_NOT_FOUND ); 1673 fail(); 1674 } 1675 catch ( ResourceDoesNotExistException e ) 1676 { 1677 assertTrue( true ); 1678 } 1679 } 1680 1681 public void testPut500() 1682 throws Exception 1683 { 1684 try 1685 { 1686 runTestPut( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); 1687 fail(); 1688 } 1689 catch ( TransferFailedException e ) 1690 { 1691 assertTrue( true ); 1692 } 1693 } 1694 1695 public void testPut429() 1696 throws Exception 1697 { 1698 1699 try 1700 { 1701 1702 StreamingWagon wagon = (StreamingWagon) getWagon(); 1703 Server server = new Server( ); 1704 final AtomicBoolean called = new AtomicBoolean(); 1705 1706 AbstractHandler handler = new AbstractHandler() 1707 { 1708 public void handle( String target, Request baseRequest, HttpServletRequest request, 1709 HttpServletResponse response ) throws IOException, ServletException 1710 { 1711 if ( called.get() ) 1712 { 1713 response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); 1714 baseRequest.setHandled( true ); 1715 } 1716 else 1717 { 1718 called.set( true ); 1719 response.setStatus( SC_TOO_MANY_REQUESTS ); 1720 baseRequest.setHandled( true ); 1721 } 1722 } 1723 }; 1724 1725 server.setHandler( handler ); 1726 addConnector( server ); 1727 server.start(); 1728 1729 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); 1730 1731 File tempFile = File.createTempFile( "wagon", "tmp" ); 1732 tempFile.deleteOnExit(); 1733 FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" ); 1734 1735 try 1736 { 1737 wagon.put( tempFile, "resource" ); 1738 fail(); 1739 } 1740 finally 1741 { 1742 wagon.disconnect(); 1743 1744 server.stop(); 1745 1746 tempFile.delete(); 1747 } 1748 1749 } 1750 catch ( TransferFailedException e ) 1751 { 1752 assertTrue( true ); 1753 } 1754 } 1755 1756 1757 private void runTestPut( int status ) 1758 throws Exception 1759 { 1760 StreamingWagon wagon = (StreamingWagon) getWagon(); 1761 1762 Server server = new Server( ); 1763 StatusHandler handler = new StatusHandler(); 1764 handler.setStatusToReturn( status ); 1765 server.setHandler( handler ); 1766 addConnector( server ); 1767 server.start(); 1768 1769 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); 1770 1771 File tempFile = File.createTempFile( "wagon", "tmp" ); 1772 tempFile.deleteOnExit(); 1773 FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" ); 1774 1775 try 1776 { 1777 wagon.put( tempFile, "resource" ); 1778 fail(); 1779 } 1780 finally 1781 { 1782 wagon.disconnect(); 1783 1784 server.stop(); 1785 1786 tempFile.delete(); 1787 } 1788 } 1789 1790 public void testSecuredPutUnauthorized() 1791 throws Exception 1792 { 1793 try 1794 { 1795 runTestSecuredPut( null ); 1796 fail(); 1797 } 1798 catch ( TransferFailedException e ) 1799 { 1800 assertTrue( true ); 1801 } 1802 } 1803 1804 public void testSecuredPutWrongPassword() 1805 throws Exception 1806 { 1807 try 1808 { 1809 AuthenticationInfo authInfo = new AuthenticationInfo(); 1810 authInfo.setUserName( "user" ); 1811 authInfo.setPassword( "admin" ); 1812 runTestSecuredPut( authInfo ); 1813 fail(); 1814 } 1815 catch ( TransferFailedException e ) 1816 { 1817 assertTrue( true ); 1818 } 1819 } 1820 1821 public void testSecuredPut() 1822 throws Exception 1823 { 1824 AuthenticationInfo authInfo = new AuthenticationInfo(); 1825 authInfo.setUserName( "user" ); 1826 authInfo.setPassword( "secret" ); 1827 runTestSecuredPut( authInfo ); 1828 } 1829 1830 public void runTestSecuredPut( AuthenticationInfo authInfo ) 1831 throws Exception 1832 { 1833 runTestSecuredPut( authInfo, 1 ); 1834 } 1835 1836 public void runTestSecuredPut( AuthenticationInfo authInfo, int putNumber ) 1837 throws Exception 1838 { 1839 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1840 Server server = new Server( ); 1841 1842 TestSecurityHandler sh = createSecurityHandler(); 1843 1844 PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) ); 1845 1846 sh.setHandler( putHandler ); 1847 server.setHandler( sh ); 1848 addConnector( server ); 1849 server.start(); 1850 1851 StreamingWagon wagon = (StreamingWagon) getWagon(); 1852 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 1853 wagon.connect( testRepository, authInfo ); 1854 try 1855 { 1856 for ( int i = 0; i < putNumber; i++ ) 1857 { 1858 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" ); 1859 sourceFile.delete(); 1860 assertFalse( sourceFile.exists() ); 1861 1862 File tempFile = File.createTempFile( "wagon", "tmp" ); 1863 tempFile.deleteOnExit(); 1864 FileUtils.fileWrite( tempFile.getAbsolutePath(), "put top secret" ); 1865 1866 try 1867 { 1868 wagon.put( tempFile, "test-secured-put-resource" ); 1869 } 1870 finally 1871 { 1872 tempFile.delete(); 1873 } 1874 1875 assertEquals( "put top secret", FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); 1876 } 1877 } 1878 finally 1879 { 1880 wagon.disconnect(); 1881 server.stop(); 1882 } 1883 assertEquals( putNumber, putHandler.putCallNumber ); 1884 testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() ); 1885 } 1886 1887 public void testNonSecuredPutFromStream() 1888 throws Exception 1889 { 1890 AuthenticationInfo authInfo = new AuthenticationInfo(); 1891 authInfo.setUserName( "user" ); 1892 authInfo.setPassword( "secret" ); 1893 runTestSecuredPutFromStream( authInfo, 1, false ); 1894 } 1895 1896 public void testSecuredPutFromStream() 1897 throws Exception 1898 { 1899 AuthenticationInfo authInfo = new AuthenticationInfo(); 1900 authInfo.setUserName( "user" ); 1901 authInfo.setPassword( "secret" ); 1902 runTestSecuredPutFromStream( authInfo, 1, true ); 1903 } 1904 1905 public void runTestSecuredPutFromStream( AuthenticationInfo authInfo, int putNumber, boolean addSecurityHandler ) 1906 throws Exception 1907 { 1908 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); 1909 Server server = new Server( ); 1910 1911 TestSecurityHandler sh = createSecurityHandler(); 1912 1913 PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) ); 1914 1915 if ( addSecurityHandler ) 1916 { 1917 sh.setHandler( putHandler ); 1918 server.setHandler( sh ); 1919 } 1920 else 1921 { 1922 server.setHandler( putHandler ); 1923 } 1924 addConnector( server ); 1925 server.start(); 1926 1927 StreamingWagon wagon = (StreamingWagon) getWagon(); 1928 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); 1929 if ( addSecurityHandler ) 1930 { 1931 wagon.connect( testRepository, authInfo ); 1932 } 1933 else 1934 { 1935 wagon.connect( testRepository ); 1936 } 1937 try 1938 { 1939 for ( int i = 0; i < putNumber; i++ ) 1940 { 1941 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" ); 1942 sourceFile.delete(); 1943 assertFalse( sourceFile.exists() ); 1944 1945 File tempFile = File.createTempFile( "wagon", "tmp" ); 1946 tempFile.deleteOnExit(); 1947 String content = "put top secret"; 1948 FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); 1949 1950 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) ) 1951 { 1952 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 ); 1953 } 1954 finally 1955 { 1956 tempFile.delete(); 1957 } 1958 1959 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); 1960 } 1961 } 1962 finally 1963 { 1964 wagon.disconnect(); 1965 server.stop(); 1966 } 1967 assertEquals( putNumber, putHandler.putCallNumber ); 1968 if ( addSecurityHandler ) 1969 { 1970 testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() ); 1971 } 1972 1973 // ensure we didn't use chunked transfer which doesn't work on ngnix 1974 for ( DeployedResource deployedResource : putHandler.deployedResources ) 1975 { 1976 if ( StringUtils.equalsIgnoreCase( "chunked", deployedResource.transferEncoding ) ) 1977 { 1978 fail( "deployedResource use chunked: " + deployedResource ); 1979 } 1980 } 1981 } 1982 1983 1984 protected abstract boolean supportPreemptiveAuthenticationPut(); 1985 1986 protected abstract boolean supportPreemptiveAuthenticationGet(); 1987 1988 protected abstract boolean supportProxyPreemptiveAuthentication(); 1989 1990 protected void testPreemptiveAuthenticationGet( TestSecurityHandler sh, boolean preemptive ) 1991 { 1992 testPreemptiveAuthentication( sh, preemptive, HttpServletResponse.SC_OK ); 1993 } 1994 1995 protected void testPreemptiveAuthenticationPut( TestSecurityHandler sh, boolean preemptive ) 1996 { 1997 testPreemptiveAuthentication( sh, preemptive, HttpServletResponse.SC_CREATED ); 1998 } 1999 2000 protected void testPreemptiveAuthentication( TestSecurityHandler sh, boolean preemptive, int statusCode ) 2001 { 2002 2003 if ( preemptive ) 2004 { 2005 assertEquals( "not 1 security handler use " + sh.handlerRequestResponses, 1, 2006 sh.handlerRequestResponses.size() ); 2007 assertEquals( statusCode, sh.handlerRequestResponses.get( 0 ).responseCode ); 2008 } 2009 else 2010 { 2011 assertEquals( "not 2 security handler use " + sh.handlerRequestResponses, 2, 2012 sh.handlerRequestResponses.size() ); 2013 assertEquals( HttpServletResponse.SC_UNAUTHORIZED, sh.handlerRequestResponses.get( 0 ).responseCode ); 2014 assertEquals( statusCode, sh.handlerRequestResponses.get( 1 ).responseCode ); 2015 2016 } 2017 } 2018 2019 static class StatusHandler 2020 extends AbstractHandler 2021 { 2022 private int status; 2023 2024 public void setStatusToReturn( int status ) 2025 { 2026 this.status = status; 2027 } 2028 2029 public void handle( String target, Request baseRequest, HttpServletRequest request, 2030 HttpServletResponse response ) throws IOException, ServletException 2031 { 2032 if ( status != 0 ) 2033 { 2034 response.setStatus( status ); 2035 baseRequest.setHandled( true ); 2036 } 2037 } 2038 } 2039 2040 static class DeployedResource 2041 { 2042 String httpMethod; 2043 2044 String requestUri; 2045 2046 String contentLength; 2047 2048 String transferEncoding; 2049 2050 DeployedResource() 2051 { 2052 // no op 2053 } 2054 2055 @Override 2056 public String toString() 2057 { 2058 final StringBuilder sb = new StringBuilder(); 2059 sb.append( "DeployedResource" ); 2060 sb.append( "{httpMethod='" ).append( httpMethod ).append( '\'' ); 2061 sb.append( ", requestUri='" ).append( requestUri ).append( '\'' ); 2062 sb.append( ", contentLength='" ).append( contentLength ).append( '\'' ); 2063 sb.append( ", transferEncoding='" ).append( transferEncoding ).append( '\'' ); 2064 sb.append( '}' ); 2065 return sb.toString(); 2066 } 2067 } 2068 2069 /** 2070 * 2071 */ 2072 @SuppressWarnings( "checkstyle:visibilitymodifier" ) 2073 public static class PutHandler 2074 extends AbstractHandler 2075 { 2076 private final File resourceBase; 2077 2078 public List<DeployedResource> deployedResources = new ArrayList<DeployedResource>(); 2079 2080 public int putCallNumber = 0; 2081 2082 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>(); 2083 2084 public PutHandler( File repositoryDirectory ) 2085 { 2086 this.resourceBase = repositoryDirectory; 2087 } 2088 2089 public void handle( String target, Request baseRequest, HttpServletRequest request, 2090 HttpServletResponse response ) throws IOException, ServletException 2091 { 2092 if ( baseRequest.isHandled() || !"PUT".equals( baseRequest.getMethod() ) ) 2093 { 2094 return; 2095 } 2096 2097 baseRequest.setHandled( true ); 2098 2099 File file = new File( resourceBase, URLDecoder.decode( request.getPathInfo() ) ); 2100 file.getParentFile().mkdirs(); 2101 OutputStream out = null; 2102 InputStream in = null; 2103 try 2104 { 2105 in = request.getInputStream(); 2106 out = new FileOutputStream( file ); 2107 IOUtil.copy( in, out ); 2108 out.close(); 2109 out = null; 2110 in.close(); 2111 in = null; 2112 } 2113 finally 2114 { 2115 IOUtil.close( in ); 2116 IOUtil.close( out ); 2117 } 2118 putCallNumber++; 2119 DeployedResource deployedResource = new DeployedResource(); 2120 2121 deployedResource.httpMethod = request.getMethod(); 2122 deployedResource.requestUri = request.getRequestURI(); 2123 deployedResource.transferEncoding = request.getHeader( "Transfer-Encoding" ); 2124 deployedResource.contentLength = request.getHeader( "Content-Length" ); 2125 deployedResources.add( deployedResource ); 2126 2127 response.setStatus( HttpServletResponse.SC_CREATED ); 2128 2129 handlerRequestResponses.add( 2130 new HandlerRequestResponse( request.getMethod(), ( (Response) response ).getStatus(), 2131 request.getRequestURI() ) ); 2132 } 2133 } 2134 2135 private static class AuthorizingProxyHandler 2136 extends TestHeaderHandler 2137 { 2138 2139 List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>(); 2140 2141 public void handle( String target, Request baseRequest, HttpServletRequest request, 2142 HttpServletResponse response ) throws IOException, ServletException 2143 { 2144 System.out.println( " handle proxy request" ); 2145 if ( request.getHeader( "Proxy-Authorization" ) == null ) 2146 { 2147 handlerRequestResponses.add( 2148 new HandlerRequestResponse( request.getMethod(), 2149 HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED, 2150 request.getRequestURI() ) ); 2151 response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED ); 2152 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" ); 2153 2154 baseRequest.setHandled( true ); 2155 return; 2156 } 2157 handlerRequestResponses.add( 2158 new HandlerRequestResponse( request.getMethod(), HttpServletResponse.SC_OK, request.getRequestURI() ) ); 2159 super.handle( target, baseRequest, request, response ); 2160 } 2161 } 2162 2163 /** 2164 * 2165 */ 2166 @SuppressWarnings( "checkstyle:visibilitymodifier" ) 2167 private static class TestHeaderHandler 2168 extends AbstractHandler 2169 { 2170 public Map<String, String> headers = Collections.emptyMap(); 2171 2172 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>(); 2173 2174 TestHeaderHandler() 2175 { 2176 } 2177 2178 public void handle( String target, Request baseRrequest, HttpServletRequest request, 2179 HttpServletResponse response ) throws IOException, ServletException 2180 { 2181 headers = new HashMap<String, String>(); 2182 for ( Enumeration<String> e = baseRrequest.getHeaderNames(); e.hasMoreElements(); ) 2183 { 2184 String name = e.nextElement(); 2185 Enumeration headerValues = baseRrequest.getHeaders( name ); 2186 // as per HTTP spec http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html 2187 // multiple values for the same header key are concatenated separated by comma 2188 // otherwise we wouldn't notice headers with same key added multiple times 2189 StringBuffer combinedHeaderValue = new StringBuffer(); 2190 for ( int i = 0; headerValues.hasMoreElements(); i++ ) 2191 { 2192 if ( i > 0 ) 2193 { 2194 combinedHeaderValue.append( "," ); 2195 } 2196 combinedHeaderValue.append( headerValues.nextElement() ); 2197 } 2198 headers.put( name, combinedHeaderValue.toString() ); 2199 } 2200 2201 response.setContentType( "text/plain" ); 2202 response.setStatus( HttpServletResponse.SC_OK ); 2203 response.getWriter().print( "Hello, World!" ); 2204 2205 handlerRequestResponses.add( 2206 new HandlerRequestResponse( baseRrequest.getMethod(), ( (Response) response ).getStatus(), 2207 baseRrequest.getRequestURI() ) ); 2208 2209 baseRrequest.setHandled( true ); 2210 } 2211 2212 } 2213 2214 protected TestSecurityHandler createSecurityHandler() 2215 { 2216 Constraint constraint = new Constraint(); 2217 constraint.setName( Constraint.__BASIC_AUTH ); 2218 constraint.setRoles( new String[]{ "admin" } ); 2219 constraint.setAuthenticate( true ); 2220 2221 ConstraintMapping cm = new ConstraintMapping(); 2222 cm.setConstraint( constraint ); 2223 cm.setPathSpec( "/*" ); 2224 2225 TestSecurityHandler sh = new TestSecurityHandler(); 2226 HashLoginService hashLoginService = new HashLoginService( "MyRealm" ); 2227 hashLoginService.putUser( "user", new Password( "secret" ), new String[] { "admin" } ); 2228 sh.setLoginService( hashLoginService ); 2229 sh.setConstraintMappings( new ConstraintMapping[]{ cm } ); 2230 sh.setAuthenticator ( new BasicAuthenticator() ); 2231 return sh; 2232 } 2233 2234 /** 2235 * 2236 */ 2237 @SuppressWarnings( "checkstyle:visibilitymodifier" ) 2238 public static class TestSecurityHandler 2239 extends ConstraintSecurityHandler 2240 { 2241 2242 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>(); 2243 2244 @Override 2245 public void handle( String target, Request baseRequest, HttpServletRequest request, 2246 HttpServletResponse response ) throws IOException, ServletException 2247 { 2248 String method = request.getMethod(); 2249 super.handle( target, baseRequest, request, response ); 2250 2251 handlerRequestResponses.add( 2252 new HandlerRequestResponse( method, ( (Response) response ).getStatus(), request.getRequestURI() ) ); 2253 } 2254 } 2255 2256 /** 2257 * 2258 */ 2259 @SuppressWarnings( "checkstyle:visibilitymodifier" ) 2260 public static class HandlerRequestResponse 2261 { 2262 public String method; 2263 2264 public int responseCode; 2265 2266 public String requestUri; 2267 2268 private HandlerRequestResponse( String method, int responseCode, String requestUri ) 2269 { 2270 this.method = method; 2271 this.responseCode = responseCode; 2272 this.requestUri = requestUri; 2273 } 2274 2275 @Override 2276 public String toString() 2277 { 2278 final StringBuilder sb = new StringBuilder(); 2279 sb.append( "HandlerRequestResponse" ); 2280 sb.append( "{method='" ).append( method ).append( '\'' ); 2281 sb.append( ", responseCode=" ).append( responseCode ); 2282 sb.append( ", requestUri='" ).append( requestUri ).append( '\'' ); 2283 sb.append( '}' ); 2284 return sb.toString(); 2285 } 2286 } 2287}