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