pax_global_header00006660000000000000000000000064122555412770014524gustar00rootroot0000000000000052 comment=a06d4dddd5a7da411ba4014eeb84dd39c3a8cf26 netty-netty-3.9.0.Final/000077500000000000000000000000001225554127700150715ustar00rootroot00000000000000netty-netty-3.9.0.Final/.fbfilter.xml000066400000000000000000000041361225554127700174720ustar00rootroot00000000000000 netty-netty-3.9.0.Final/.fbprefs000066400000000000000000000207721225554127700165310ustar00rootroot00000000000000#FindBugs User Preferences #Wed Mar 04 19:28:55 KST 2009 detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true detectorBCPMethodReturnCheck=BCPMethodReturnCheck|true detectorBadAppletConstructor=BadAppletConstructor|true detectorBadResultSetAccess=BadResultSetAccess|true detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true detectorBadUseOfReturnValue=BadUseOfReturnValue|true detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true detectorBooleanReturnNull=BooleanReturnNull|true detectorBuildInterproceduralCallGraph=BuildInterproceduralCallGraph|true detectorBuildObligationPolicyDatabase=BuildObligationPolicyDatabase|true detectorCallToUnsupportedMethod=CallToUnsupportedMethod|true detectorCalledMethods=CalledMethods|true detectorCheckCalls=CheckCalls|false detectorCheckExpectedWarnings=CheckExpectedWarnings|false detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true detectorCheckTypeQualifiers=CheckTypeQualifiers|true detectorCloneIdiom=CloneIdiom|true detectorComparatorIdiom=ComparatorIdiom|true detectorConfusedInheritance=ConfusedInheritance|true detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true detectorCrossSiteScripting=CrossSiteScripting|true detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true detectorDontUseEnum=DontUseEnum|true detectorDroppedException=DroppedException|true detectorDumbMethodInvocations=DumbMethodInvocations|true detectorDumbMethods=DumbMethods|true detectorDuplicateBranches=DuplicateBranches|true detectorEmptyZipFileEntry=EmptyZipFileEntry|true detectorEqStringTest=EqStringTest|true detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true detectorFieldItemSummary=FieldItemSummary|true detectorFinalizerNullsFields=FinalizerNullsFields|true detectorFindBadCast=FindBadCast|true detectorFindBadCast2=FindBadCast2|true detectorFindBadEqualsImplementation=FindBadEqualsImplementation|true detectorFindBadForLoop=FindBadForLoop|true detectorFindBugsSummaryStats=FindBugsSummaryStats|true detectorFindCircularDependencies=FindCircularDependencies|false detectorFindDeadLocalStores=FindDeadLocalStores|true detectorFindDoubleCheck=FindDoubleCheck|true detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true detectorFindFinalizeInvocations=FindFinalizeInvocations|true detectorFindFloatEquality=FindFloatEquality|true detectorFindFloatMath=FindFloatMath|false detectorFindHEmismatch=FindHEmismatch|true detectorFindInconsistentSync2=FindInconsistentSync2|true detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true detectorFindMaskedFields=FindMaskedFields|true detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true detectorFindNakedNotify=FindNakedNotify|true detectorFindNonSerializableStoreIntoSession=FindNonSerializableStoreIntoSession|true detectorFindNonSerializableValuePassedToWriteObject=FindNonSerializableValuePassedToWriteObject|true detectorFindNonShortCircuit=FindNonShortCircuit|true detectorFindNullDeref=FindNullDeref|true detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true detectorFindOpenStream=FindOpenStream|true detectorFindPuzzlers=FindPuzzlers|true detectorFindRefComparison=FindRefComparison|true detectorFindReturnRef=FindReturnRef|true detectorFindRunInvocations=FindRunInvocations|true detectorFindSelfComparison=FindSelfComparison|true detectorFindSelfComparison2=FindSelfComparison2|true detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true detectorFindSpinLoop=FindSpinLoop|true detectorFindSqlInjection=FindSqlInjection|true detectorFindTwoLockWait=FindTwoLockWait|true detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true detectorFindUnconditionalWait=FindUnconditionalWait|true detectorFindUninitializedGet=FindUninitializedGet|true detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true detectorFindUnreleasedLock=FindUnreleasedLock|true detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true detectorFindUnsyncGet=FindUnsyncGet|true detectorFindUselessControlFlow=FindUselessControlFlow|true detectorFormatStringChecker=FormatStringChecker|true detectorHugeSharedStringConstants=HugeSharedStringConstants|true detectorIDivResultCastToDouble=IDivResultCastToDouble|true detectorIncompatMask=IncompatMask|true detectorInconsistentAnnotations=InconsistentAnnotations|true detectorInefficientMemberAccess=InefficientMemberAccess|true detectorInefficientToArray=InefficientToArray|true detectorInfiniteLoop=InfiniteLoop|true detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|true detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true detectorInitializationChain=InitializationChain|true detectorInstantiateStaticClass=InstantiateStaticClass|true detectorInvalidJUnitTest=InvalidJUnitTest|true detectorIteratorIdioms=IteratorIdioms|true detectorLazyInit=LazyInit|true detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true detectorLockedFields=LockedFields|true detectorMethodReturnCheck=MethodReturnCheck|true detectorMethods=Methods|true detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true detectorMutableLock=MutableLock|true detectorMutableStaticFields=MutableStaticFields|true detectorNaming=Naming|true detectorNoise=Noise|false detectorNoiseNullDeref=NoiseNullDeref|false detectorNoteAnnotationRetention=NoteAnnotationRetention|true detectorNoteCheckReturnValue=NoteCheckReturnValue|true detectorNoteCheckReturnValueAnnotations=NoteCheckReturnValueAnnotations|true detectorNoteDirectlyRelevantTypeQualifiers=NoteDirectlyRelevantTypeQualifiers|true detectorNoteJCIPAnnotation=NoteJCIPAnnotation|true detectorNoteNonNullAnnotations=NoteNonNullAnnotations|true detectorNoteNonnullReturnValues=NoteNonnullReturnValues|true detectorNoteSuppressedWarnings=NoteSuppressedWarnings|true detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true detectorNumberConstructor=NumberConstructor|true detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true detectorPublicSemaphores=PublicSemaphores|true detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true detectorRedundantInterfaces=RedundantInterfaces|true detectorReflectiveClasses=ReflectiveClasses|true detectorRepeatedConditionals=RepeatedConditionals|true detectorResolveAllReferences=ResolveAllReferences|true detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true detectorSerializableIdiom=SerializableIdiom|true detectorStartInConstructor=StartInConstructor|true detectorStaticCalendarDetector=StaticCalendarDetector|true detectorStringConcatenation=StringConcatenation|true detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true detectorSwitchFallthrough=SwitchFallthrough|true detectorSynchronizationOnSharedBuiltinConstant=SynchronizationOnSharedBuiltinConstant|true detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true detectorTestASM=TestASM|false detectorTestDataflowAnalysis=TestDataflowAnalysis|false detectorTestingGround=TestingGround|false detectorTrainFieldStoreTypes=TrainFieldStoreTypes|true detectorTrainNonNullAnnotations=TrainNonNullAnnotations|true detectorTrainUnconditionalDerefParams=TrainUnconditionalDerefParams|true detectorURLProblems=URLProblems|true detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true detectorUnnecessaryMath=UnnecessaryMath|true detectorUnreadFields=UnreadFields|true detectorUseObjectEquals=UseObjectEquals|true detectorUselessSubclassMethod=UselessSubclassMethod|true detectorVarArgsProblems=VarArgsProblems|true detectorVolatileUsage=VolatileUsage|true detectorWaitInLoop=WaitInLoop|true detectorWrongMapIterator=WrongMapIterator|true detectorXMLFactoryBypass=XMLFactoryBypass|true detector_threshold=3 effort=max excludefilter0=.fbfilter.xml filter_settings=Low|BAD_PRACTICE,CORRECTNESS,EXPERIMENTAL,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false filter_settings_neg=NOISE| run_at_full_build=true netty-netty-3.9.0.Final/.gitignore000066400000000000000000000002121225554127700170540ustar00rootroot00000000000000/.project /.classpath /.settings /target /reports /src/main/java/org/jboss/netty/util/Version.java /*.iml /*.ipr /*.iws /.metadata /.idea/netty-netty-3.9.0.Final/.travis.yml000066400000000000000000000002521225554127700172010ustar00rootroot00000000000000language: java jdk: - oraclejdk7 - openjdk7 branches: only: - master - 3 - 3.5 before_install: 'mvn -version' install: 'mvn -DskipTests clean install' netty-netty-3.9.0.Final/LICENSE.txt000066400000000000000000000261361225554127700167240ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. netty-netty-3.9.0.Final/NOTICE.txt000066400000000000000000000066771225554127700166330ustar00rootroot00000000000000 The Netty Project ================= Please visit the Netty web site for more information: * http://netty.io/ Copyright 2011 The Netty Project The Netty Project licenses this file to you under the Apache License, version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Also, please refer to each LICENSE..txt file, which is located in the 'license' directory of the distribution file, for the license terms of the components that this product depends on. ------------------------------------------------------------------------------- This product contains the extensions to Java Collections Framework which has been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: * LICENSE: * license/LICENSE.jsr166y.txt (Public Domain) * HOMEPAGE: * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ This product contains a modified version of Robert Harder's Public Domain Base64 Encoder and Decoder, which can be obtained at: * LICENSE: * license/LICENSE.base64.txt (Public Domain) * HOMEPAGE: * http://iharder.sourceforge.net/current/java/base64/ This product contains a modified version of 'JZlib', a re-implementation of zlib in pure Java, which can be obtained at: * LICENSE: * license/LICENSE.jzlib.txt (BSD Style License) * HOMEPAGE: * http://www.jcraft.com/jzlib/ This product optionally depends on 'Protocol Buffers', Google's data interchange format, which can be obtained at: * LICENSE: * license/LICENSE.protobuf.txt (New BSD License) * HOMEPAGE: * http://code.google.com/p/protobuf/ This product optionally depends on 'SLF4J', a simple logging facade for Java, which can be obtained at: * LICENSE: * license/LICENSE.slf4j.txt (MIT License) * HOMEPAGE: * http://www.slf4j.org/ This product optionally depends on 'Apache Commons Logging', a logging framework, which can be obtained at: * LICENSE: * license/LICENSE.commons-logging.txt (Apache License 2.0) * HOMEPAGE: * http://commons.apache.org/logging/ This product optionally depends on 'Apache Log4J', a logging framework, which can be obtained at: * LICENSE: * license/LICENSE.log4j.txt (Apache License 2.0) * HOMEPAGE: * http://logging.apache.org/log4j/ This product optionally depends on 'JBoss Logging', a logging framework, which can be obtained at: * LICENSE: * license/LICENSE.jboss-logging.txt (GNU LGPL 2.1) * HOMEPAGE: * http://anonsvn.jboss.org/repos/common/common-logging-spi/ This product optionally depends on 'Apache Felix', an open source OSGi framework implementation, which can be obtained at: * LICENSE: * license/LICENSE.felix.txt (Apache License 2.0) * HOMEPAGE: * http://felix.apache.org/ This product optionally depends on 'Webbit', a Java event based WebSocket and HTTP server: * LICENSE: * license/LICENSE.webbit.txt (BSD License) * HOMEPAGE: * https://github.com/joewalnes/webbit netty-netty-3.9.0.Final/license/000077500000000000000000000000001225554127700165135ustar00rootroot00000000000000netty-netty-3.9.0.Final/license/LICENSE.base64.txt000066400000000000000000000030701225554127700214210ustar00rootroot00000000000000The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below. A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain. Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuate of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work. Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived. netty-netty-3.9.0.Final/license/LICENSE.commons-logging.txt000066400000000000000000000236761225554127700234520ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS netty-netty-3.9.0.Final/license/LICENSE.felix.txt000066400000000000000000000236761225554127700214620ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS netty-netty-3.9.0.Final/license/LICENSE.jboss-logging.txt000066400000000000000000000635111225554127700231070ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! netty-netty-3.9.0.Final/license/LICENSE.jsr166y.txt000066400000000000000000000030701225554127700215610ustar00rootroot00000000000000The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below. A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain. Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work. Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived. netty-netty-3.9.0.Final/license/LICENSE.jzlib.txt000066400000000000000000000026711225554127700214550ustar00rootroot00000000000000Copyright (c) 2000,2001,2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. netty-netty-3.9.0.Final/license/LICENSE.log4j.txt000066400000000000000000000236761225554127700213720ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS netty-netty-3.9.0.Final/license/LICENSE.protobuf.txt000066400000000000000000000033041225554127700221750ustar00rootroot00000000000000Copyright 2008, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Code generated by the Protocol Buffer compiler is owned by the owner of the input file used when generating it. This code is not standalone and requires a support library to be linked with it. This support library is itself covered by the above license. netty-netty-3.9.0.Final/license/LICENSE.slf4j.txt000066400000000000000000000022631225554127700213620ustar00rootroot00000000000000/* * Copyright (c) 2004-2007 QOS.ch * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ netty-netty-3.9.0.Final/license/LICENSE.webbit.txt000066400000000000000000000030761225554127700216170ustar00rootroot00000000000000(BSD License: http://www.opensource.org/licenses/bsd-license) Copyright (c) 2011, Joe Walnes, Aslak Hellesøy and contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Webbit nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. netty-netty-3.9.0.Final/pom.xml000066400000000000000000000631341225554127700164150ustar00rootroot00000000000000 4.0.0 org.sonatype.oss oss-parent 7 io.netty netty bundle 3.9.0.Final The Netty Project http://netty.io/ The Netty project is an effort to provide an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance and high scalability protocol servers and clients. In other words, Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server. The Netty Project http://netty.io/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 2008 https://github.com/netty/netty scm:git:git://github.com/netty/netty.git scm:git:ssh://git@github.com/netty/netty.git netty.io The Netty Project Contributors netty@googlegroups.com http://netty.io/ The Netty Project http://netty.io/ org.jboss.marshalling jboss-marshalling ${jboss.marshalling.version} compile true com.google.protobuf protobuf-java 2.5.0 compile true javax.servlet servlet-api 2.5 compile true javax.activation activation 1.1.1 compile true org.apache.felix org.osgi.core 1.4.0 compile true org.apache.felix org.osgi.compendium 1.4.0 compile true org.apache.felix javax.servlet org.apache.felix org.osgi.foundation org.slf4j slf4j-api 1.6.4 compile true commons-logging commons-logging 1.1.1 compile true org.jboss.logging jboss-logging-spi 2.1.2.GA compile true log4j log4j 1.2.16 compile mail javax.mail jms javax.jms jmxtools com.sun.jdmk jmxri com.sun.jmx true junit junit 4.10 test org.easymock easymock 3.1 test org.easymock easymockclassextension 3.1 test org.slf4j slf4j-simple 1.6.4 test org.jboss.marshalling jboss-marshalling-serial ${jboss.marshalling.version} test org.jboss.marshalling jboss-marshalling-river ${jboss.marshalling.version} test false 1.3.14.GA ${basedir}/src/main/resources ${basedir}/target/license org.eclipse.m2e lifecycle-mapping 1.0.0 org.apache.maven.plugins maven-antrun-plugin [1.7,) run org.apache.maven.plugins maven-checkstyle-plugin [2.8,) check maven-enforcer-plugin 1.0.1 enforce-tools enforce [1.7.0,) [3.0.5,) maven-compiler-plugin 2.3.2 UTF-8 1.5 1.5 true true true true org.codehaus.mojo animal-sniffer-maven-plugin 1.7 org.codehaus.mojo.signature java15 1.0 sun.misc.Unsafe java.util.zip.Deflater java.util.concurrent.LinkedTransferQueue java.nio.channels.DatagramChannel java.nio.channels.MembershipKey java.net.StandardSocketOptions java.net.StandardProtocolFamily java.io.ObjectStreamClass java.net.IDN process-classes check maven-resources-plugin 2.5 UTF-8 copy-legal-info validate copy-resources ${basedir}/target/license/META-INF ${basedir} false LICENSE.txt NOTICE.txt license/*.txt maven-surefire-plugin 2.10 never **/Abstract* **/TestUtil* random org.apache.felix maven-bundle-plugin 2.3.4 true org.jboss.netty ${project.url} org.jboss.netty.container.osgi.NettyBundleActivator !org.jboss.netty.example.*, !org.jboss.netty.util.internal.*, org.jboss.netty.*;version=${project.version} org.jboss.netty.example.*, org.jboss.netty.util.internal.*, *;resolution:=optional registered registered org.jboss.netty.util.Version maven-source-plugin 2.1.2 attach-source package jar true maven-antrun-plugin 1.7 write-version validate run Build number: ${buildNumber} remove-examples package run org.apache.ant ant 1.8.2 org.apache.ant ant-launcher 1.8.2 ant-contrib ant-contrib 1.0b3 ant ant maven-javadoc-plugin 2.8 attach-javadoc package jar org.jboss.apiviz.APIviz org.jboss.apiviz apiviz 1.3.2.GA true ${basedir}/src/javadoc true true ${project.build.directory}/api UTF-8 UTF-8 true false false true ${basedir}/src/javadoc/overview.html ${project.name} API Reference (${project.version}) ${project.name} API Reference (${project.version}) -link http://docs.oracle.com/javase/7/docs/api/ -link http://code.google.com/apis/protocolbuffers/docs/reference/java/ -link http://docs.oracle.com/javaee/6/api/ -link http://www.osgi.org/javadoc/r4v43/core/ -link http://www.slf4j.org/apidocs/ -link http://commons.apache.org/logging/commons-logging-1.1.1/apidocs/ -link http://logging.apache.org/log4j/1.2/apidocs/ -group "Low-level data representation" org.jboss.netty.buffer* -group "Central interface for all I/O operations" org.jboss.netty.channel* -group "Client & Server bootstrapping utilities" org.jboss.netty.bootstrap* -group "Reusable I/O event interceptors" org.jboss.netty.handler* -group "Miscellaneous" org.jboss.netty.logging*:org.jboss.netty.util* -sourceclasspath ${project.build.outputDirectory} -nopackagediagram UTF-8 en_US org.jboss.netty.example*:org.jboss.netty.container*:org.jboss.netty.util.internal* maven-jxr-plugin 2.2 generate-xref package jxr UTF-8 UTF-8 true ${project.build.directory}/xref ${project.build.directory}/api ${project.name} Source Xref (${project.version}) ${project.name} Source Xref (${project.version}) maven-assembly-plugin 2.2.1 generate-distribution package single ${basedir}/src/assembly/default.xml ${attach-distribution} true gnu maven-checkstyle-plugin 2.9.1 check-style check validate true true true true io/netty/checkstyle.xml ${project.groupId} netty-build 16 netty-netty-3.9.0.Final/src/000077500000000000000000000000001225554127700156605ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/assembly/000077500000000000000000000000001225554127700174775ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/assembly/default.xml000066400000000000000000000042001225554127700216410ustar00rootroot00000000000000 dist tar.bz2 false **/README* **/LICENSE* **/NOTICE* **/COPYRIGHT* **/*.txt **/*.xml **/license/** **/src/** **/bin/** **/target/** **/.*/** target jar ${project.build.finalName}*.jar ${project.build.finalName}*-javadoc.jar target/api doc/api **/** target/xref doc/xref **/** netty-netty-3.9.0.Final/src/javadoc/000077500000000000000000000000001225554127700172675ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/javadoc/overview.html000066400000000000000000000025741225554127700220330ustar00rootroot00000000000000 The Netty Project API Reference

The Netty project is an effort to provide an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance and high scalability protocol servers and clients. In other words, Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP/IP socket server.

netty-netty-3.9.0.Final/src/main/000077500000000000000000000000001225554127700166045ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/000077500000000000000000000000001225554127700175255ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/000077500000000000000000000000001225554127700203145ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/000077500000000000000000000000001225554127700214345ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/000077500000000000000000000000001225554127700225775ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/bootstrap/000077500000000000000000000000001225554127700246145ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/bootstrap/Bootstrap.java000066400000000000000000000506221225554127700274410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.util.ExternalResourceReleasable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import static org.jboss.netty.channel.Channels.*; /** * A helper class which initializes a {@link Channel}. This class provides * the common data structure for its subclasses which actually initialize * {@link Channel}s and their child {@link Channel}s using the common data * structure. Please refer to {@link ClientBootstrap}, {@link ServerBootstrap}, * and {@link ConnectionlessBootstrap} for client side, server-side, and * connectionless (e.g. UDP) channel initialization respectively. * * @apiviz.uses org.jboss.netty.channel.ChannelFactory */ public class Bootstrap implements ExternalResourceReleasable { private volatile ChannelFactory factory; private volatile ChannelPipeline pipeline = pipeline(); private volatile ChannelPipelineFactory pipelineFactory = pipelineFactory(pipeline); private volatile Map options = new HashMap(); /** * Creates a new instance with no {@link ChannelFactory} set. * {@link #setFactory(ChannelFactory)} must be called at once before any * I/O operation is requested. */ protected Bootstrap() { } /** * Creates a new instance with the specified initial {@link ChannelFactory}. */ protected Bootstrap(ChannelFactory channelFactory) { setFactory(channelFactory); } /** * Returns the {@link ChannelFactory} that will be used to perform an * I/O operation. * * @throws IllegalStateException * if the factory is not set for this bootstrap yet. * The factory can be set in the constructor or * {@link #setFactory(ChannelFactory)}. */ public ChannelFactory getFactory() { ChannelFactory factory = this.factory; if (factory == null) { throw new IllegalStateException( "factory is not set yet."); } return factory; } /** * Sets the {@link ChannelFactory} that will be used to perform an I/O * operation. This method can be called only once and can't be called at * all if the factory was specified in the constructor. * * @throws IllegalStateException * if the factory is already set */ public void setFactory(ChannelFactory factory) { if (factory == null) { throw new NullPointerException("factory"); } if (this.factory != null) { throw new IllegalStateException( "factory can't change once set."); } this.factory = factory; } /** * Returns the default {@link ChannelPipeline} which is cloned when a new * {@link Channel} is created. {@link Bootstrap} creates a new pipeline * which has the same entries with the returned pipeline for a new * {@link Channel}. *

* Please note that this method is a convenience method that works only * when 1) you create only one channel from this bootstrap (e.g. * one-time client-side or connectionless channel) or 2) all handlers * in the pipeline is stateless. You have to use * {@link #setPipelineFactory(ChannelPipelineFactory)} if 1) your * pipeline contains a stateful {@link ChannelHandler} and 2) one or * more channels are going to be created by this bootstrap (e.g. server-side * channels). * * @return the default {@link ChannelPipeline} * * @throws IllegalStateException * if {@link #setPipelineFactory(ChannelPipelineFactory)} was * called by a user last time. */ public ChannelPipeline getPipeline() { ChannelPipeline pipeline = this.pipeline; if (pipeline == null) { throw new IllegalStateException( "getPipeline() cannot be called " + "if setPipelineFactory() was called."); } return pipeline; } /** * Sets the default {@link ChannelPipeline} which is cloned when a new * {@link Channel} is created. {@link Bootstrap} creates a new pipeline * which has the same entries with the specified pipeline for a new channel. *

* Calling this method also sets the {@code pipelineFactory} property to an * internal {@link ChannelPipelineFactory} implementation which returns * a shallow copy of the specified pipeline. *

* Please note that this method is a convenience method that works only * when 1) you create only one channel from this bootstrap (e.g. * one-time client-side or connectionless channel) or 2) all handlers * in the pipeline is stateless. You have to use * {@link #setPipelineFactory(ChannelPipelineFactory)} if 1) your * pipeline contains a stateful {@link ChannelHandler} and 2) one or * more channels are going to be created by this bootstrap (e.g. server-side * channels). */ public void setPipeline(ChannelPipeline pipeline) { if (pipeline == null) { throw new NullPointerException("pipeline"); } this.pipeline = pipeline; pipelineFactory = pipelineFactory(pipeline); } /** * Dependency injection friendly convenience method for * {@link #getPipeline()} which returns the default pipeline of this * bootstrap as an ordered map. *

* Please note that this method is a convenience method that works only * when 1) you create only one channel from this bootstrap (e.g. * one-time client-side or connectionless channel) or 2) all handlers * in the pipeline is stateless. You have to use * {@link #setPipelineFactory(ChannelPipelineFactory)} if 1) your * pipeline contains a stateful {@link ChannelHandler} and 2) one or * more channels are going to be created by this bootstrap (e.g. server-side * channels). * * @throws IllegalStateException * if {@link #setPipelineFactory(ChannelPipelineFactory)} was * called by a user last time. */ public Map getPipelineAsMap() { ChannelPipeline pipeline = this.pipeline; if (pipeline == null) { throw new IllegalStateException("pipelineFactory in use"); } return pipeline.toMap(); } /** * Dependency injection friendly convenience method for * {@link #setPipeline(ChannelPipeline)} which sets the default pipeline of * this bootstrap from an ordered map. *

* Please note that this method is a convenience method that works only * when 1) you create only one channel from this bootstrap (e.g. * one-time client-side or connectionless channel) or 2) all handlers * in the pipeline is stateless. You have to use * {@link #setPipelineFactory(ChannelPipelineFactory)} if 1) your * pipeline contains a stateful {@link ChannelHandler} and 2) one or * more channels are going to be created by this bootstrap (e.g. server-side * channels). * * @throws IllegalArgumentException * if the specified map is not an ordered map */ public void setPipelineAsMap(Map pipelineMap) { if (pipelineMap == null) { throw new NullPointerException("pipelineMap"); } if (!isOrderedMap(pipelineMap)) { throw new IllegalArgumentException( "pipelineMap is not an ordered map. " + "Please use " + LinkedHashMap.class.getName() + '.'); } ChannelPipeline pipeline = pipeline(); for (Map.Entry e: pipelineMap.entrySet()) { pipeline.addLast(e.getKey(), e.getValue()); } setPipeline(pipeline); } /** * Returns the {@link ChannelPipelineFactory} which creates a new * {@link ChannelPipeline} for each new {@link Channel}. * * @see #getPipeline() */ public ChannelPipelineFactory getPipelineFactory() { return pipelineFactory; } /** * Sets the {@link ChannelPipelineFactory} which creates a new * {@link ChannelPipeline} for each new {@link Channel}. Calling this * method invalidates the current {@code pipeline} property of this * bootstrap. Subsequent {@link #getPipeline()} and {@link #getPipelineAsMap()} * calls will raise {@link IllegalStateException}. * * @see #setPipeline(ChannelPipeline) * @see #setPipelineAsMap(Map) */ public void setPipelineFactory(ChannelPipelineFactory pipelineFactory) { if (pipelineFactory == null) { throw new NullPointerException("pipelineFactory"); } pipeline = null; this.pipelineFactory = pipelineFactory; } /** * Returns the options which configures a new {@link Channel} and its * child {@link Channel}s. The names of the child {@link Channel} options * are prepended with {@code "child."} (e.g. {@code "child.keepAlive"}). */ public Map getOptions() { return new TreeMap(options); } /** * Sets the options which configures a new {@link Channel} and its child * {@link Channel}s. To set the options of a child {@link Channel}, prepend * {@code "child."} to the option name (e.g. {@code "child.keepAlive"}). */ public void setOptions(Map options) { if (options == null) { throw new NullPointerException("options"); } this.options = new HashMap(options); } /** * Returns the value of the option with the specified key. To retrieve * the option value of a child {@link Channel}, prepend {@code "child."} * to the option name (e.g. {@code "child.keepAlive"}). * * @param key the option name * * @return the option value if the option is found. * {@code null} otherwise. */ public Object getOption(String key) { if (key == null) { throw new NullPointerException("key"); } return options.get(key); } /** * Sets an option with the specified key and value. If there's already * an option with the same key, it is replaced with the new value. If the * specified value is {@code null}, an existing option with the specified * key is removed. To set the option value of a child {@link Channel}, * prepend {@code "child."} to the option name (e.g. {@code "child.keepAlive"}). * * @param key the option name * @param value the option value */ public void setOption(String key, Object value) { if (key == null) { throw new NullPointerException("key"); } if (value == null) { options.remove(key); } else { options.put(key, value); } } /** * This method simply delegates the call to * {@link ChannelFactory#releaseExternalResources()}. */ public void releaseExternalResources() { ChannelFactory factory = this.factory; if (factory != null) { factory.releaseExternalResources(); } } /** * This method simply delegates the call to * {@link ChannelFactory#shutdown()}. */ public void shutdown() { ChannelFactory factory = this.factory; if (factory != null) { factory.shutdown(); } } /** * Returns {@code true} if and only if the specified {@code map} is an * ordered map, like {@link LinkedHashMap} is. */ @SuppressWarnings({ "unchecked", "rawtypes" }) static boolean isOrderedMap(Map map) { Class mapType = map.getClass(); if (LinkedHashMap.class.isAssignableFrom(mapType)) { // LinkedHashMap is an ordered map. return true; } // Not a LinkedHashMap - start autodetection. // Detect Apache Commons Collections OrderedMap implementations. Class type = mapType; while (type != null) { for (Class i: type.getInterfaces()) { if (i.getName().endsWith("OrderedMap")) { // Seems like it's an ordered map - guessed from that // it implements OrderedMap interface. return true; } } type = type.getSuperclass(); } // Does not implement OrderedMap interface. As a last resort, try to // create a new instance and test if the insertion order is maintained. Map newMap; try { newMap = (Map) mapType.newInstance(); } catch (Exception e) { // No default constructor - cannot proceed anymore. return false; } // Run some tests. List expectedKeys = new ArrayList(); String dummyValue = "dummyValue"; for (short element: ORDER_TEST_SAMPLES) { String key = String.valueOf(element); newMap.put(key, dummyValue); expectedKeys.add(key); Iterator it = expectedKeys.iterator(); for (Object actualKey: newMap.keySet()) { if (!it.next().equals(actualKey)) { // Did not pass the test. return false; } } } // The specified map passed the insertion order test. return true; } private static final short[] ORDER_TEST_SAMPLES = { 682, 807, 637, 358, 570, 828, 407, 319, 105, 41, 563, 544, 518, 298, 418, 50, 156, 769, 984, 503, 191, 578, 309, 710, 327, 720, 591, 939, 374, 707, 43, 463, 227, 174, 30, 531, 135, 930, 190, 823, 925, 835, 328, 239, 415, 500, 144, 460, 83, 774, 921, 4, 95, 468, 687, 493, 991, 436, 245, 742, 149, 821, 142, 782, 297, 918, 917, 424, 978, 992, 79, 906, 535, 515, 850, 80, 125, 378, 307, 883, 836, 160, 27, 630, 668, 226, 560, 698, 467, 829, 476, 163, 977, 367, 325, 184, 204, 312, 486, 53, 179, 592, 252, 750, 893, 517, 937, 124, 148, 719, 973, 566, 405, 449, 452, 777, 349, 761, 167, 783, 220, 802, 117, 604, 216, 363, 120, 621, 219, 182, 817, 244, 438, 465, 934, 888, 628, 209, 631, 17, 870, 679, 826, 945, 680, 848, 974, 573, 626, 865, 109, 317, 91, 494, 965, 473, 725, 388, 302, 936, 660, 150, 122, 949, 295, 392, 63, 634, 772, 143, 990, 895, 538, 59, 541, 32, 669, 321, 811, 756, 82, 955, 953, 636, 390, 162, 688, 444, 70, 590, 183, 745, 543, 666, 951, 642, 747, 765, 98, 469, 884, 929, 178, 721, 994, 840, 353, 726, 940, 759, 624, 919, 667, 629, 272, 979, 326, 608, 453, 11, 322, 347, 647, 354, 381, 746, 472, 890, 249, 536, 733, 404, 170, 959, 34, 899, 195, 651, 140, 856, 201, 237, 51, 933, 268, 849, 294, 115, 157, 14, 854, 373, 186, 872, 71, 523, 931, 952, 655, 561, 607, 862, 554, 661, 313, 909, 511, 752, 986, 311, 287, 775, 505, 878, 422, 103, 299, 119, 107, 344, 487, 776, 445, 218, 549, 697, 454, 6, 462, 455, 52, 481, 594, 126, 112, 66, 877, 172, 153, 912, 834, 741, 610, 915, 964, 831, 575, 714, 250, 461, 814, 913, 369, 542, 882, 851, 427, 838, 867, 507, 434, 569, 20, 950, 792, 605, 798, 962, 923, 258, 972, 762, 809, 843, 674, 448, 280, 495, 285, 822, 283, 147, 451, 993, 794, 982, 748, 189, 274, 96, 73, 810, 401, 261, 277, 346, 527, 645, 601, 868, 248, 879, 371, 428, 559, 278, 265, 62, 225, 853, 483, 771, 9, 8, 339, 653, 263, 28, 477, 995, 208, 880, 292, 480, 516, 457, 286, 897, 21, 852, 971, 658, 623, 528, 316, 471, 860, 306, 638, 711, 875, 671, 108, 158, 646, 24, 257, 724, 193, 341, 902, 599, 565, 334, 506, 684, 960, 780, 429, 801, 910, 308, 383, 901, 489, 81, 512, 164, 755, 514, 723, 141, 296, 958, 686, 15, 799, 579, 598, 558, 414, 64, 420, 730, 256, 131, 45, 129, 259, 338, 999, 175, 740, 790, 324, 985, 896, 482, 841, 606, 377, 111, 372, 699, 988, 233, 243, 203, 781, 969, 903, 662, 632, 301, 44, 981, 36, 412, 946, 816, 284, 447, 214, 672, 758, 954, 804, 2, 928, 886, 421, 596, 574, 16, 892, 68, 546, 522, 490, 873, 656, 696, 864, 130, 40, 393, 926, 394, 932, 876, 664, 293, 154, 916, 55, 196, 842, 498, 177, 948, 540, 127, 271, 113, 844, 576, 132, 943, 12, 123, 291, 31, 212, 529, 547, 171, 582, 609, 793, 830, 221, 440, 568, 118, 406, 194, 827, 360, 622, 389, 800, 571, 213, 262, 403, 408, 881, 289, 635, 967, 432, 376, 649, 832, 857, 717, 145, 510, 159, 980, 683, 580, 484, 379, 246, 88, 567, 320, 643, 7, 924, 397, 10, 787, 845, 779, 670, 716, 19, 600, 382, 0, 210, 665, 228, 97, 266, 90, 304, 456, 180, 152, 425, 310, 768, 223, 702, 997, 577, 663, 290, 537, 416, 426, 914, 691, 23, 281, 497, 508, 48, 681, 581, 728, 99, 795, 530, 871, 957, 889, 206, 813, 839, 709, 805, 253, 151, 613, 65, 654, 93, 639, 784, 891, 352, 67, 430, 754, 76, 187, 443, 676, 362, 961, 874, 330, 331, 384, 85, 217, 855, 818, 738, 361, 314, 3, 615, 520, 355, 920, 689, 22, 188, 49, 904, 935, 136, 475, 693, 749, 519, 812, 100, 207, 963, 364, 464, 572, 731, 230, 833, 385, 499, 545, 273, 232, 398, 478, 975, 564, 399, 504, 35, 562, 938, 211, 26, 337, 54, 614, 586, 433, 450, 763, 238, 305, 941, 370, 885, 837, 234, 110, 137, 395, 368, 695, 342, 907, 396, 474, 176, 737, 796, 446, 37, 894, 727, 648, 431, 1, 366, 525, 553, 704, 329, 627, 479, 33, 492, 260, 241, 86, 185, 491, 966, 247, 13, 587, 602, 409, 335, 650, 235, 611, 470, 442, 597, 254, 343, 539, 146, 585, 593, 641, 770, 94, 976, 705, 181, 255, 315, 718, 526, 987, 692, 983, 595, 898, 282, 133, 439, 633, 534, 861, 269, 619, 677, 502, 375, 224, 806, 869, 417, 584, 612, 803, 58, 84, 788, 797, 38, 700, 751, 603, 652, 57, 240, 947, 350, 270, 333, 116, 736, 69, 74, 104, 767, 318, 735, 859, 357, 555, 411, 267, 712, 675, 532, 825, 496, 927, 942, 102, 46, 192, 114, 744, 138, 998, 72, 617, 134, 846, 166, 77, 900, 5, 303, 387, 400, 47, 729, 922, 222, 197, 351, 509, 524, 165, 485, 300, 944, 380, 625, 778, 685, 29, 589, 766, 161, 391, 423, 42, 734, 552, 215, 824, 908, 229, 89, 251, 199, 616, 78, 644, 242, 722, 25, 437, 732, 956, 275, 200, 970, 753, 791, 336, 556, 847, 703, 236, 715, 75, 863, 713, 785, 911, 786, 620, 551, 413, 39, 739, 820, 808, 764, 701, 819, 173, 989, 345, 690, 459, 60, 106, 887, 996, 365, 673, 968, 513, 18, 419, 550, 588, 435, 264, 789, 340, 659, 466, 356, 288, 56, 708, 557, 488, 760, 332, 402, 168, 202, 521, 757, 205, 706, 441, 773, 231, 583, 386, 678, 618, 815, 279, 87, 533, 61, 548, 92, 169, 694, 905, 198, 121, 410, 139, 657, 640, 743, 128, 458, 866, 501, 348, 155, 276, 101, 858, 323, 359, }; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/bootstrap/ClientBootstrap.java000066400000000000000000000253141225554127700306000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineException; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import java.net.InetSocketAddress; import java.net.SocketAddress; /** * A helper class which creates a new client-side {@link Channel} and makes a * connection attempt. * *

Configuring a channel

* * {@link #setOption(String, Object) Options} are used to configure a channel: * *
 * {@link ClientBootstrap} b = ...;
 *
 * // Options for a new channel
 * b.setOption("remoteAddress", new {@link InetSocketAddress}("example.com", 8080));
 * b.setOption("tcpNoDelay", true);
 * b.setOption("receiveBufferSize", 1048576);
 * 
* * For the detailed list of available options, please refer to * {@link ChannelConfig} and its sub-types. * *

Configuring a channel pipeline

* * Every channel has its own {@link ChannelPipeline} and you can configure it * in two ways. * * The recommended approach is to specify a {@link ChannelPipelineFactory} by * calling {@link #setPipelineFactory(ChannelPipelineFactory)}. * *
 * {@link ClientBootstrap} b = ...;
 * b.setPipelineFactory(new MyPipelineFactory());
 *
 * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
 *   public {@link ChannelPipeline} getPipeline() throws Exception {
 *     // Create and configure a new pipeline for a new channel.
 *     {@link ChannelPipeline} p = {@link Channels}.pipeline();
 *     p.addLast("encoder", new EncodingHandler());
 *     p.addLast("decoder", new DecodingHandler());
 *     p.addLast("logic",   new LogicHandler());
 *     return p;
 *   }
 * }
 * 
*

* The alternative approach, which works only in a certain situation, is to use * the default pipeline and let the bootstrap to shallow-copy the default * pipeline for each new channel: * *

 * {@link ClientBootstrap} b = ...;
 * {@link ChannelPipeline} p = b.getPipeline();
 *
 * // Add handlers to the default pipeline.
 * p.addLast("encoder", new EncodingHandler());
 * p.addLast("decoder", new DecodingHandler());
 * p.addLast("logic",   new LogicHandler());
 * 
* * Please note 'shallow-copy' here means that the added {@link ChannelHandler}s * are not cloned but only their references are added to the new pipeline. * Therefore, you cannot use this approach if you are going to open more than * one {@link Channel}s or run a server that accepts incoming connections to * create its child channels. * *

Applying different settings for different {@link Channel}s

* * {@link ClientBootstrap} is just a helper class. It neither allocates nor * manages any resources. What manages the resources is the * {@link ChannelFactory} implementation you specified in the constructor of * {@link ClientBootstrap}. Therefore, it is OK to create as many * {@link ClientBootstrap} instances as you want with the same * {@link ChannelFactory} to apply different settings for different * {@link Channel}s. * * @apiviz.landmark */ public class ClientBootstrap extends Bootstrap { /** * Creates a new instance with no {@link ChannelFactory} set. * {@link #setFactory(ChannelFactory)} must be called before any I/O * operation is requested. */ public ClientBootstrap() { } /** * Creates a new instance with the specified initial {@link ChannelFactory}. */ public ClientBootstrap(ChannelFactory channelFactory) { super(channelFactory); } /** * Attempts a new connection with the current {@code "remoteAddress"} and * {@code "localAddress"} option. If the {@code "localAddress"} option is * not set, the local address of a new channel is determined automatically. * This method is similar to the following code: * *
     * {@link ClientBootstrap} b = ...;
     * b.connect(b.getOption("remoteAddress"), b.getOption("localAddress"));
     * 
* * @return a future object which notifies when this connection attempt * succeeds or fails * * @throws IllegalStateException * if {@code "remoteAddress"} option was not set * @throws ClassCastException * if {@code "remoteAddress"} or {@code "localAddress"} option's * value is neither a {@link SocketAddress} nor {@code null} * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture connect() { SocketAddress remoteAddress = (SocketAddress) getOption("remoteAddress"); if (remoteAddress == null) { throw new IllegalStateException("remoteAddress option is not set."); } return connect(remoteAddress); } /** * Attempts a new connection with the specified {@code remoteAddress} and * the current {@code "localAddress"} option. If the {@code "localAddress"} * option is not set, the local address of a new channel is determined * automatically. This method is identical with the following code: * *
     * {@link ClientBootstrap} b = ...;
     * b.connect(remoteAddress, b.getOption("localAddress"));
     * 
* * @return a future object which notifies when this connection attempt * succeeds or fails * * @throws ClassCastException * if {@code "localAddress"} option's value is * neither a {@link SocketAddress} nor {@code null} * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture connect(SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } SocketAddress localAddress = (SocketAddress) getOption("localAddress"); return connect(remoteAddress, localAddress); } /** * Attempts a new connection with the specified {@code remoteAddress} and * the specified {@code localAddress}. If the specified local address is * {@code null}, the local address of a new channel is determined * automatically. * * @return a future object which notifies when this connection attempt * succeeds or fails * * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture connect(final SocketAddress remoteAddress, final SocketAddress localAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } ChannelPipeline pipeline; try { pipeline = getPipelineFactory().getPipeline(); } catch (Exception e) { throw new ChannelPipelineException("Failed to initialize a pipeline.", e); } // Set the options. Channel ch = getFactory().newChannel(pipeline); boolean success = false; try { ch.getConfig().setOptions(getOptions()); success = true; } finally { if (!success) { ch.close(); } } // Bind. if (localAddress != null) { ch.bind(localAddress); } // Connect. return ch.connect(remoteAddress); } /** * Attempts to bind a channel with the specified {@code localAddress}. later the channel can * be connected to a remoteAddress by calling {@link Channel#connect(SocketAddress)}.This method * is useful where bind and connect need to be done in separate steps. *

* For an instance, a user can set an attachment to the {@link Channel} via * {@link Channel#setAttachment(Object)} before beginning a connection attempt so that the user can access * the attachment once the connection is established: * *

     *  ChannelFuture bindFuture = bootstrap.bind(new InetSocketAddress("192.168.0.15", 0));
     *  Channel channel = bindFuture.getChannel();
     *  channel.setAttachment(dataObj);
     *  channel.connect(new InetSocketAddress("192.168.0.30", 8080));
     * 
* * The attachment can be accessed then in the handler like the following: * *
     *  public class YourHandler extends SimpleChannelUpstreamHandler {
     *      public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
     *          Object dataObject = ctx.getChannel().getAttachment();
     *      }
     *  }
     *
     * 
* * @return a future object which notifies when this bind attempt * succeeds or fails * * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture bind(final SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } ChannelPipeline pipeline; try { pipeline = getPipelineFactory().getPipeline(); } catch (Exception e) { throw new ChannelPipelineException("Failed to initialize a pipeline.", e); } // Set the options. Channel ch = getFactory().newChannel(pipeline); boolean success = false; try { ch.getConfig().setOptions(getOptions()); success = true; } finally { if (!success) { ch.close(); } } // Bind. return ch.bind(localAddress); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/bootstrap/ConnectionlessBootstrap.java000066400000000000000000000267051225554127700323550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineException; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; /** * A helper class which creates a new server-side {@link Channel} for a * connectionless transport. * *

Only for connectionless transports

* * This bootstrap is for connectionless transports only such as UDP/IP. * Use {@link ServerBootstrap} instead for connection oriented transports. * Do not use this helper if you are using a connection oriented transport such * as TCP/IP and local transport which accepts an incoming connection and lets * the accepted child channels handle received messages. * *

Configuring channels

* * {@link #setOption(String, Object) Options} are used to configure a channel: * *
 * {@link ConnectionlessBootstrap} b = ...;
 *
 * // Options for a new channel
 * b.setOption("localAddress", new {@link InetSocketAddress}(8080));
 * b.setOption("tcpNoDelay", true);
 * b.setOption("receiveBufferSize", 1048576);
 * 
* * For the detailed list of available options, please refer to * {@link ChannelConfig} and its sub-types. * *

Configuring a channel pipeline

* * Every channel has its own {@link ChannelPipeline} and you can configure it * in two ways. * * The recommended approach is to specify a {@link ChannelPipelineFactory} by * calling {@link #setPipelineFactory(ChannelPipelineFactory)}. * *
 * {@link ConnectionlessBootstrap} b = ...;
 * b.setPipelineFactory(new MyPipelineFactory());
 *
 * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
 *   public {@link ChannelPipeline} getPipeline() throws Exception {
 *     // Create and configure a new pipeline for a new channel.
 *     {@link ChannelPipeline} p = {@link Channels}.pipeline();
 *     p.addLast("encoder", new EncodingHandler());
 *     p.addLast("decoder", new DecodingHandler());
 *     p.addLast("logic",   new LogicHandler());
 *     return p;
 *   }
 * }
 * 
*

* The alternative approach, which works only in a certain situation, is to use * the default pipeline and let the bootstrap to shallow-copy the default * pipeline for each new channel: * *

 * {@link ConnectionlessBootstrap} b = ...;
 * {@link ChannelPipeline} p = b.getPipeline();
 *
 * // Add handlers to the default pipeline.
 * p.addLast("encoder", new EncodingHandler());
 * p.addLast("decoder", new DecodingHandler());
 * p.addLast("logic",   new LogicHandler());
 * 
* * Please note 'shallow-copy' here means that the added {@link ChannelHandler}s * are not cloned but only their references are added to the new pipeline. * Therefore, you cannot use this approach if you are going to open more than * one {@link Channel}s or run a server that accepts incoming connections to * create its child channels. * *

Applying different settings for different {@link Channel}s

* * {@link ConnectionlessBootstrap} is just a helper class. It neither * allocates nor manages any resources. What manages the resources is the * {@link ChannelFactory} implementation you specified in the constructor of * {@link ConnectionlessBootstrap}. Therefore, it is OK to create as * many {@link ConnectionlessBootstrap} instances as you want with the same * {@link ChannelFactory} to apply different settings for different * {@link Channel}s. * * @apiviz.landmark */ public class ConnectionlessBootstrap extends Bootstrap { /** * Creates a new instance with no {@link ChannelFactory} set. * {@link #setFactory(ChannelFactory)} must be called before any I/O * operation is requested. */ public ConnectionlessBootstrap() { } /** * Creates a new instance with the specified initial {@link ChannelFactory}. */ public ConnectionlessBootstrap(ChannelFactory channelFactory) { super(channelFactory); } /** * Creates a new channel which is bound to the local address which was * specified in the current {@code "localAddress"} option. This method is * similar to the following code: * *
     * {@link ConnectionlessBootstrap} b = ...;
     * b.bind(b.getOption("localAddress"));
     * 
* * @return a new bound channel which accepts incoming connections * * @throws IllegalStateException * if {@code "localAddress"} option was not set * @throws ClassCastException * if {@code "localAddress"} option's value is * neither a {@link SocketAddress} nor {@code null} * @throws ChannelException * if failed to create a new channel and * bind it to the local address */ public Channel bind() { SocketAddress localAddress = (SocketAddress) getOption("localAddress"); if (localAddress == null) { throw new IllegalStateException("localAddress option is not set."); } return bind(localAddress); } /** * Creates a new channel which is bound to the specified local address. * * @return a new bound channel which accepts incoming connections * * @throws ChannelException * if failed to create a new channel and * bind it to the local address */ public Channel bind(final SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } ChannelPipeline pipeline; try { pipeline = getPipelineFactory().getPipeline(); } catch (Exception e) { throw new ChannelPipelineException("Failed to initialize a pipeline.", e); } Channel ch = getFactory().newChannel(pipeline); // Apply options. boolean success = false; try { ch.getConfig().setOptions(getOptions()); success = true; } finally { if (!success) { ch.close(); } } // Bind ChannelFuture future = ch.bind(localAddress); // Wait for the future. future.awaitUninterruptibly(); if (!future.isSuccess()) { future.getChannel().close().awaitUninterruptibly(); throw new ChannelException("Failed to bind to: " + localAddress, future.getCause()); } return ch; } /** * Creates a new connected channel with the current {@code "remoteAddress"} * and {@code "localAddress"} option. If the {@code "localAddress"} option * is not set, the local address of a new channel is determined * automatically. This method is similar to the following code: * *
     * {@link ConnectionlessBootstrap} b = ...;
     * b.connect(b.getOption("remoteAddress"), b.getOption("localAddress"));
     * 
* * @return a future object which notifies when the creation of the connected * channel succeeds or fails * * @throws IllegalStateException * if {@code "remoteAddress"} option was not set * @throws ClassCastException * if {@code "remoteAddress"} or {@code "localAddress"} option's * value is neither a {@link SocketAddress} nor {@code null} * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture connect() { SocketAddress remoteAddress = (SocketAddress) getOption("remoteAddress"); if (remoteAddress == null) { throw new IllegalStateException("remoteAddress option is not set."); } return connect(remoteAddress); } /** * Creates a new connected channel with the specified * {@code "remoteAddress"} and the current {@code "localAddress"} option. * If the {@code "localAddress"} option is not set, the local address of * a new channel is determined automatically. This method is identical * with the following code: * *
     * {@link ConnectionlessBootstrap} b = ...;
     * b.connect(remoteAddress, b.getOption("localAddress"));
     * 
* * @return a future object which notifies when the creation of the connected * channel succeeds or fails * * @throws ClassCastException * if {@code "localAddress"} option's value is * neither a {@link SocketAddress} nor {@code null} * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture connect(SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remotedAddress"); } SocketAddress localAddress = (SocketAddress) getOption("localAddress"); return connect(remoteAddress, localAddress); } /** * Creates a new connected channel with the specified * {@code "remoteAddress"} and the specified {@code "localAddress"}. * If the specified local address is {@code null}, the local address of a * new channel is determined automatically. * * @return a future object which notifies when the creation of the connected * channel succeeds or fails * * @throws ChannelPipelineException * if this bootstrap's {@link #setPipelineFactory(ChannelPipelineFactory) pipelineFactory} * failed to create a new {@link ChannelPipeline} */ public ChannelFuture connect(final SocketAddress remoteAddress, final SocketAddress localAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } ChannelPipeline pipeline; try { pipeline = getPipelineFactory().getPipeline(); } catch (Exception e) { throw new ChannelPipelineException("Failed to initialize a pipeline.", e); } // Set the options. Channel ch = getFactory().newChannel(pipeline); boolean success = false; try { ch.getConfig().setOptions(getOptions()); success = true; } finally { if (!success) { ch.close(); } } // Bind. if (localAddress != null) { ch.bind(localAddress); } // Connect. return ch.connect(remoteAddress); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/bootstrap/ServerBootstrap.java000066400000000000000000000364561225554127700306410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ChildChannelStateEvent; import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.ServerChannelFactory; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import static org.jboss.netty.channel.Channels.*; /** * A helper class which creates a new server-side {@link Channel} and accepts * incoming connections. * *

Only for connection oriented transports

* * This bootstrap is for connection oriented transports only such as TCP/IP * and local transport. Use {@link ConnectionlessBootstrap} instead for * connectionless transports. Do not use this helper if you are using a * connectionless transport such as UDP/IP which does not accept an incoming * connection but receives messages by itself without creating a child channel. * *

Parent channel and its children

* * A parent channel is a channel which is supposed to accept incoming * connections. It is created by this bootstrap's {@link ChannelFactory} via * {@link #bind()} and {@link #bind(SocketAddress)}. *

* Once successfully bound, the parent channel starts to accept incoming * connections, and the accepted connections become the children of the * parent channel. * *

Configuring channels

* * {@link #setOption(String, Object) Options} are used to configure both a * parent channel and its child channels. To configure the child channels, * prepend {@code "child."} prefix to the actual option names of a child * channel: * *
 * {@link ServerBootstrap} b = ...;
 *
 * // Options for a parent channel
 * b.setOption("localAddress", new {@link InetSocketAddress}(8080));
 * b.setOption("reuseAddress", true);
 *
 * // Options for its children
 * b.setOption("child.tcpNoDelay", true);
 * b.setOption("child.receiveBufferSize", 1048576);
 * 
* * For the detailed list of available options, please refer to * {@link ChannelConfig} and its sub-types. * *

Configuring a parent channel pipeline

* * It is rare to customize the pipeline of a parent channel because what it is * supposed to do is very typical. However, you might want to add a handler * to deal with some special needs such as degrading the process * UID from * a superuser to a * normal user and changing the current VM security manager for better * security. To support such a case, * the {@link #setParentHandler(ChannelHandler) parentHandler} property is * provided. * *

Configuring a child channel pipeline

* * Every channel has its own {@link ChannelPipeline} and you can configure it * in two ways. * * The recommended approach is to specify a {@link ChannelPipelineFactory} by * calling {@link #setPipelineFactory(ChannelPipelineFactory)}. * *
 * {@link ServerBootstrap} b = ...;
 * b.setPipelineFactory(new MyPipelineFactory());
 *
 * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
 *   public {@link ChannelPipeline} getPipeline() throws Exception {
 *     // Create and configure a new pipeline for a new channel.
 *     {@link ChannelPipeline} p = {@link Channels}.pipeline();
 *     p.addLast("encoder", new EncodingHandler());
 *     p.addLast("decoder", new DecodingHandler());
 *     p.addLast("logic",   new LogicHandler());
 *     return p;
 *   }
 * }
 * 
*

* The alternative approach, which works only in a certain situation, is to use * the default pipeline and let the bootstrap to shallow-copy the default * pipeline for each new channel: * *

 * {@link ServerBootstrap} b = ...;
 * {@link ChannelPipeline} p = b.getPipeline();
 *
 * // Add handlers to the default pipeline.
 * p.addLast("encoder", new EncodingHandler());
 * p.addLast("decoder", new DecodingHandler());
 * p.addLast("logic",   new LogicHandler());
 * 
* * Please note 'shallow-copy' here means that the added {@link ChannelHandler}s * are not cloned but only their references are added to the new pipeline. * Therefore, you cannot use this approach if you are going to open more than * one {@link Channel}s or run a server that accepts incoming connections to * create its child channels. * *

Applying different settings for different {@link Channel}s

* * {@link ServerBootstrap} is just a helper class. It neither allocates nor * manages any resources. What manages the resources is the * {@link ChannelFactory} implementation you specified in the constructor of * {@link ServerBootstrap}. Therefore, it is OK to create as many * {@link ServerBootstrap} instances as you want with the same * {@link ChannelFactory} to apply different settings for different * {@link Channel}s. * * @apiviz.landmark */ public class ServerBootstrap extends Bootstrap { private volatile ChannelHandler parentHandler; /** * Creates a new instance with no {@link ChannelFactory} set. * {@link #setFactory(ChannelFactory)} must be called before any I/O * operation is requested. */ public ServerBootstrap() { } /** * Creates a new instance with the specified initial {@link ChannelFactory}. */ public ServerBootstrap(ChannelFactory channelFactory) { super(channelFactory); } /** * Sets the {@link ServerChannelFactory} that will be used to perform an I/O * operation. This method can be called only once and can't be called at * all if the factory was specified in the constructor. * * @throws IllegalStateException * if the factory is already set * @throws IllegalArgumentException * if the specified {@code factory} is not a * {@link ServerChannelFactory} */ @Override public void setFactory(ChannelFactory factory) { if (factory == null) { throw new NullPointerException("factory"); } if (!(factory instanceof ServerChannelFactory)) { throw new IllegalArgumentException( "factory must be a " + ServerChannelFactory.class.getSimpleName() + ": " + factory.getClass()); } super.setFactory(factory); } /** * Returns an optional {@link ChannelHandler} which intercepts an event * of a newly bound server-side channel which accepts incoming connections. * * @return the parent channel handler. * {@code null} if no parent channel handler is set. */ public ChannelHandler getParentHandler() { return parentHandler; } /** * Sets an optional {@link ChannelHandler} which intercepts an event of * a newly bound server-side channel which accepts incoming connections. * * @param parentHandler * the parent channel handler. * {@code null} to unset the current parent channel handler. */ public void setParentHandler(ChannelHandler parentHandler) { this.parentHandler = parentHandler; } /** * Creates a new channel which is bound to the local address which was * specified in the current {@code "localAddress"} option. This method is * similar to the following code: * *
     * {@link ServerBootstrap} b = ...;
     * b.bind(b.getOption("localAddress"));
     * 
* * This operation will block until the channel is bound. * * @return a new bound channel which accepts incoming connections * * @throws IllegalStateException * if {@code "localAddress"} option was not set * @throws ClassCastException * if {@code "localAddress"} option's value is * neither a {@link SocketAddress} nor {@code null} * @throws ChannelException * if failed to create a new channel and * bind it to the local address */ public Channel bind() { SocketAddress localAddress = (SocketAddress) getOption("localAddress"); if (localAddress == null) { throw new IllegalStateException("localAddress option is not set."); } return bind(localAddress); } /** * Creates a new channel which is bound to the specified local address. This operation will block until * the channel is bound. * * @return a new bound channel which accepts incoming connections * * @throws ChannelException * if failed to create a new channel and * bind it to the local address */ public Channel bind(final SocketAddress localAddress) { ChannelFuture future = bindAsync(localAddress); // Wait for the future. future.awaitUninterruptibly(); if (!future.isSuccess()) { future.getChannel().close().awaitUninterruptibly(); throw new ChannelException("Failed to bind to: " + localAddress, future.getCause()); } return future.getChannel(); } /** * Bind a channel asynchronous to the local address * specified in the current {@code "localAddress"} option. This method is * similar to the following code: * *
     * {@link ServerBootstrap} b = ...;
     * b.bindAsync(b.getOption("localAddress"));
     * 
* * * @return a new {@link ChannelFuture} which will be notified once the Channel is * bound and accepts incoming connections * * @throws IllegalStateException * if {@code "localAddress"} option was not set * @throws ClassCastException * if {@code "localAddress"} option's value is * neither a {@link SocketAddress} nor {@code null} * @throws ChannelException * if failed to create a new channel and * bind it to the local address */ public ChannelFuture bindAsync() { SocketAddress localAddress = (SocketAddress) getOption("localAddress"); if (localAddress == null) { throw new IllegalStateException("localAddress option is not set."); } return bindAsync(localAddress); } /** * Bind a channel asynchronous to the specified local address. * * @return a new {@link ChannelFuture} which will be notified once the Channel is * bound and accepts incoming connections * */ public ChannelFuture bindAsync(final SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } Binder binder = new Binder(localAddress); ChannelHandler parentHandler = getParentHandler(); ChannelPipeline bossPipeline = pipeline(); bossPipeline.addLast("binder", binder); if (parentHandler != null) { bossPipeline.addLast("userHandler", parentHandler); } Channel channel = getFactory().newChannel(bossPipeline); final ChannelFuture bfuture = new DefaultChannelFuture(channel, false); binder.bindFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { bfuture.setSuccess(); } else { // Call close on bind failure bfuture.getChannel().close(); bfuture.setFailure(future.getCause()); } } }); return bfuture; } private final class Binder extends SimpleChannelUpstreamHandler { private final SocketAddress localAddress; private final Map childOptions = new HashMap(); private final DefaultChannelFuture bindFuture = new DefaultChannelFuture(null, false); Binder(SocketAddress localAddress) { this.localAddress = localAddress; } @Override public void channelOpen( ChannelHandlerContext ctx, ChannelStateEvent evt) { try { evt.getChannel().getConfig().setPipelineFactory(getPipelineFactory()); // Split options into two categories: parent and child. Map allOptions = getOptions(); Map parentOptions = new HashMap(); for (Entry e: allOptions.entrySet()) { if (e.getKey().startsWith("child.")) { childOptions.put( e.getKey().substring(6), e.getValue()); } else if (!"pipelineFactory".equals(e.getKey())) { parentOptions.put(e.getKey(), e.getValue()); } } // Apply parent options. evt.getChannel().getConfig().setOptions(parentOptions); } finally { ctx.sendUpstream(evt); } evt.getChannel().bind(localAddress).addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { bindFuture.setSuccess(); } else { bindFuture.setFailure(future.getCause()); } } }); } @Override public void childChannelOpen( ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { // Apply child options. try { e.getChildChannel().getConfig().setOptions(childOptions); } catch (Throwable t) { fireExceptionCaught(e.getChildChannel(), t); } ctx.sendUpstream(e); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { bindFuture.setFailure(e.getCause()); ctx.sendUpstream(e); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/bootstrap/package-info.java000066400000000000000000000015641225554127700300110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * IoC/DI friendly helper classes which enable an easy implementation of * typical client side and server side channel initialization. * * @apiviz.landmark * @apiviz.exclude ^org\.jboss\.netty\.util\. */ package org.jboss.netty.bootstrap; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/000077500000000000000000000000001225554127700240505ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/AbstractChannelBuffer.java000066400000000000000000000464341225554127700311140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.charset.Charset; import java.util.NoSuchElementException; /** * A skeletal implementation of a buffer. */ public abstract class AbstractChannelBuffer implements ChannelBuffer { private int readerIndex; private int writerIndex; private int markedReaderIndex; private int markedWriterIndex; public int readerIndex() { return readerIndex; } public void readerIndex(int readerIndex) { if (readerIndex < 0 || readerIndex > writerIndex) { throw new IndexOutOfBoundsException(); } this.readerIndex = readerIndex; } public int writerIndex() { return writerIndex; } public void writerIndex(int writerIndex) { if (writerIndex < readerIndex || writerIndex > capacity()) { throw new IndexOutOfBoundsException("Invalid readerIndex: " + readerIndex + " - Maximum is " + writerIndex); } this.writerIndex = writerIndex; } public void setIndex(int readerIndex, int writerIndex) { if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) { throw new IndexOutOfBoundsException("Invalid writerIndex: " + writerIndex + " - Maximum is " + readerIndex + " or " + capacity()); } this.readerIndex = readerIndex; this.writerIndex = writerIndex; } public void clear() { readerIndex = writerIndex = 0; } public boolean readable() { return readableBytes() > 0; } public boolean writable() { return writableBytes() > 0; } public int readableBytes() { return writerIndex - readerIndex; } public int writableBytes() { return capacity() - writerIndex; } public void markReaderIndex() { markedReaderIndex = readerIndex; } public void resetReaderIndex() { readerIndex(markedReaderIndex); } public void markWriterIndex() { markedWriterIndex = writerIndex; } public void resetWriterIndex() { writerIndex = markedWriterIndex; } public void discardReadBytes() { if (readerIndex == 0) { return; } setBytes(0, this, readerIndex, writerIndex - readerIndex); writerIndex -= readerIndex; markedReaderIndex = Math.max(markedReaderIndex - readerIndex, 0); markedWriterIndex = Math.max(markedWriterIndex - readerIndex, 0); readerIndex = 0; } public void ensureWritableBytes(int writableBytes) { if (writableBytes > writableBytes()) { throw new IndexOutOfBoundsException("Writable bytes exceeded: Got " + writableBytes + ", maximum is " + writableBytes()); } } public short getUnsignedByte(int index) { return (short) (getByte(index) & 0xFF); } public int getUnsignedShort(int index) { return getShort(index) & 0xFFFF; } public int getMedium(int index) { int value = getUnsignedMedium(index); if ((value & 0x800000) != 0) { value |= 0xff000000; } return value; } public long getUnsignedInt(int index) { return getInt(index) & 0xFFFFFFFFL; } public char getChar(int index) { return (char) getShort(index); } public float getFloat(int index) { return Float.intBitsToFloat(getInt(index)); } public double getDouble(int index) { return Double.longBitsToDouble(getLong(index)); } public void getBytes(int index, byte[] dst) { getBytes(index, dst, 0, dst.length); } public void getBytes(int index, ChannelBuffer dst) { getBytes(index, dst, dst.writableBytes()); } public void getBytes(int index, ChannelBuffer dst, int length) { if (length > dst.writableBytes()) { throw new IndexOutOfBoundsException("Too many bytes to be read: Need " + length + ", maximum is " + dst.writableBytes()); } getBytes(index, dst, dst.writerIndex(), length); dst.writerIndex(dst.writerIndex() + length); } public void setChar(int index, int value) { setShort(index, value); } public void setFloat(int index, float value) { setInt(index, Float.floatToRawIntBits(value)); } public void setDouble(int index, double value) { setLong(index, Double.doubleToRawLongBits(value)); } public void setBytes(int index, byte[] src) { setBytes(index, src, 0, src.length); } public void setBytes(int index, ChannelBuffer src) { setBytes(index, src, src.readableBytes()); } public void setBytes(int index, ChannelBuffer src, int length) { if (length > src.readableBytes()) { throw new IndexOutOfBoundsException("Too many bytes to write: Need " + length + ", maximum is " + src.readableBytes()); } setBytes(index, src, src.readerIndex(), length); src.readerIndex(src.readerIndex() + length); } public void setZero(int index, int length) { if (length == 0) { return; } if (length < 0) { throw new IllegalArgumentException( "length must be 0 or greater than 0."); } int nLong = length >>> 3; int nBytes = length & 7; for (int i = nLong; i > 0; i --) { setLong(index, 0); index += 8; } if (nBytes == 4) { setInt(index, 0); } else if (nBytes < 4) { for (int i = nBytes; i > 0; i --) { setByte(index, (byte) 0); index ++; } } else { setInt(index, 0); index += 4; for (int i = nBytes - 4; i > 0; i --) { setByte(index, (byte) 0); index ++; } } } public byte readByte() { if (readerIndex == writerIndex) { throw new IndexOutOfBoundsException("Readable byte limit exceeded: " + readerIndex); } return getByte(readerIndex ++); } public short readUnsignedByte() { return (short) (readByte() & 0xFF); } public short readShort() { checkReadableBytes(2); short v = getShort(readerIndex); readerIndex += 2; return v; } public int readUnsignedShort() { return readShort() & 0xFFFF; } public int readMedium() { int value = readUnsignedMedium(); if ((value & 0x800000) != 0) { value |= 0xff000000; } return value; } public int readUnsignedMedium() { checkReadableBytes(3); int v = getUnsignedMedium(readerIndex); readerIndex += 3; return v; } public int readInt() { checkReadableBytes(4); int v = getInt(readerIndex); readerIndex += 4; return v; } public long readUnsignedInt() { return readInt() & 0xFFFFFFFFL; } public long readLong() { checkReadableBytes(8); long v = getLong(readerIndex); readerIndex += 8; return v; } public char readChar() { return (char) readShort(); } public float readFloat() { return Float.intBitsToFloat(readInt()); } public double readDouble() { return Double.longBitsToDouble(readLong()); } public ChannelBuffer readBytes(int length) { checkReadableBytes(length); if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer buf = factory().getBuffer(order(), length); buf.writeBytes(this, readerIndex, length); readerIndex += length; return buf; } @Deprecated public ChannelBuffer readBytes(ChannelBufferIndexFinder endIndexFinder) { int endIndex = indexOf(readerIndex, writerIndex, endIndexFinder); if (endIndex < 0) { throw new NoSuchElementException(); } return readBytes(endIndex - readerIndex); } public ChannelBuffer readSlice(int length) { ChannelBuffer slice = slice(readerIndex, length); readerIndex += length; return slice; } @Deprecated public ChannelBuffer readSlice(ChannelBufferIndexFinder endIndexFinder) { int endIndex = indexOf(readerIndex, writerIndex, endIndexFinder); if (endIndex < 0) { throw new NoSuchElementException(); } return readSlice(endIndex - readerIndex); } public void readBytes(byte[] dst, int dstIndex, int length) { checkReadableBytes(length); getBytes(readerIndex, dst, dstIndex, length); readerIndex += length; } public void readBytes(byte[] dst) { readBytes(dst, 0, dst.length); } public void readBytes(ChannelBuffer dst) { readBytes(dst, dst.writableBytes()); } public void readBytes(ChannelBuffer dst, int length) { if (length > dst.writableBytes()) { throw new IndexOutOfBoundsException("Too many bytes to be read: Need " + length + ", maximum is " + dst.writableBytes()); } readBytes(dst, dst.writerIndex(), length); dst.writerIndex(dst.writerIndex() + length); } public void readBytes(ChannelBuffer dst, int dstIndex, int length) { checkReadableBytes(length); getBytes(readerIndex, dst, dstIndex, length); readerIndex += length; } public void readBytes(ByteBuffer dst) { int length = dst.remaining(); checkReadableBytes(length); getBytes(readerIndex, dst); readerIndex += length; } public int readBytes(GatheringByteChannel out, int length) throws IOException { checkReadableBytes(length); int readBytes = getBytes(readerIndex, out, length); readerIndex += readBytes; return readBytes; } public void readBytes(OutputStream out, int length) throws IOException { checkReadableBytes(length); getBytes(readerIndex, out, length); readerIndex += length; } public void skipBytes(int length) { int newReaderIndex = readerIndex + length; if (newReaderIndex > writerIndex) { throw new IndexOutOfBoundsException("Readable bytes exceeded - Need " + newReaderIndex + ", maximum is " + writerIndex); } readerIndex = newReaderIndex; } @Deprecated public int skipBytes(ChannelBufferIndexFinder firstIndexFinder) { int oldReaderIndex = readerIndex; int newReaderIndex = indexOf(oldReaderIndex, writerIndex, firstIndexFinder); if (newReaderIndex < 0) { throw new NoSuchElementException(); } readerIndex(newReaderIndex); return newReaderIndex - oldReaderIndex; } public void writeByte(int value) { setByte(writerIndex, value); writerIndex++; } public void writeShort(int value) { setShort(writerIndex, value); writerIndex += 2; } public void writeMedium(int value) { setMedium(writerIndex, value); writerIndex += 3; } public void writeInt(int value) { setInt(writerIndex, value); writerIndex += 4; } public void writeLong(long value) { setLong(writerIndex, value); writerIndex += 8; } public void writeChar(int value) { writeShort(value); } public void writeFloat(float value) { writeInt(Float.floatToRawIntBits(value)); } public void writeDouble(double value) { writeLong(Double.doubleToRawLongBits(value)); } public void writeBytes(byte[] src, int srcIndex, int length) { setBytes(writerIndex, src, srcIndex, length); writerIndex += length; } public void writeBytes(byte[] src) { writeBytes(src, 0, src.length); } public void writeBytes(ChannelBuffer src) { writeBytes(src, src.readableBytes()); } public void writeBytes(ChannelBuffer src, int length) { if (length > src.readableBytes()) { throw new IndexOutOfBoundsException("Too many bytes to write - Need " + length + ", maximum is " + src.readableBytes()); } writeBytes(src, src.readerIndex(), length); src.readerIndex(src.readerIndex() + length); } public void writeBytes(ChannelBuffer src, int srcIndex, int length) { setBytes(writerIndex, src, srcIndex, length); writerIndex += length; } public void writeBytes(ByteBuffer src) { int length = src.remaining(); setBytes(writerIndex, src); writerIndex += length; } public int writeBytes(InputStream in, int length) throws IOException { int writtenBytes = setBytes(writerIndex, in, length); if (writtenBytes > 0) { writerIndex += writtenBytes; } return writtenBytes; } public int writeBytes(ScatteringByteChannel in, int length) throws IOException { int writtenBytes = setBytes(writerIndex, in, length); if (writtenBytes > 0) { writerIndex += writtenBytes; } return writtenBytes; } public void writeZero(int length) { if (length == 0) { return; } if (length < 0) { throw new IllegalArgumentException( "length must be 0 or greater than 0."); } int nLong = length >>> 3; int nBytes = length & 7; for (int i = nLong; i > 0; i --) { writeLong(0); } if (nBytes == 4) { writeInt(0); } else if (nBytes < 4) { for (int i = nBytes; i > 0; i --) { writeByte((byte) 0); } } else { writeInt(0); for (int i = nBytes - 4; i > 0; i --) { writeByte((byte) 0); } } } public ChannelBuffer copy() { return copy(readerIndex, readableBytes()); } public ChannelBuffer slice() { return slice(readerIndex, readableBytes()); } public ByteBuffer toByteBuffer() { return toByteBuffer(readerIndex, readableBytes()); } public ByteBuffer[] toByteBuffers() { return toByteBuffers(readerIndex, readableBytes()); } public ByteBuffer[] toByteBuffers(int index, int length) { return new ByteBuffer[] { toByteBuffer(index, length) }; } public String toString(Charset charset) { return toString(readerIndex, readableBytes(), charset); } public String toString(int index, int length, Charset charset) { if (length == 0) { return ""; } return ChannelBuffers.decodeString( toByteBuffer(index, length), charset); } @Deprecated public String toString(int index, int length, String charsetName, ChannelBufferIndexFinder terminatorFinder) { if (terminatorFinder == null) { return toString(index, length, charsetName); } int terminatorIndex = indexOf(index, index + length, terminatorFinder); if (terminatorIndex < 0) { return toString(index, length, charsetName); } return toString(index, terminatorIndex - index, charsetName); } @Deprecated public String toString(int index, int length, String charsetName) { return toString(index, length, Charset.forName(charsetName)); } @Deprecated public String toString(String charsetName, ChannelBufferIndexFinder terminatorFinder) { return toString(readerIndex, readableBytes(), charsetName, terminatorFinder); } @Deprecated public String toString(String charsetName) { return toString(Charset.forName(charsetName)); } public int indexOf(int fromIndex, int toIndex, byte value) { return ChannelBuffers.indexOf(this, fromIndex, toIndex, value); } public int indexOf(int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) { return ChannelBuffers.indexOf(this, fromIndex, toIndex, indexFinder); } public int bytesBefore(byte value) { return bytesBefore(readerIndex(), readableBytes(), value); } public int bytesBefore(ChannelBufferIndexFinder indexFinder) { return bytesBefore(readerIndex(), readableBytes(), indexFinder); } public int bytesBefore(int length, byte value) { checkReadableBytes(length); return bytesBefore(readerIndex(), length, value); } public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) { checkReadableBytes(length); return bytesBefore(readerIndex(), length, indexFinder); } public int bytesBefore(int index, int length, byte value) { if (index < 0 || length < 0 || index + length > capacity()) { throw new IndexOutOfBoundsException(); } int endIndex = indexOf(index, index + length, value); if (endIndex < 0) { return -1; } return endIndex - index; } public int bytesBefore(int index, int length, ChannelBufferIndexFinder indexFinder) { if (index < 0 || length < 0 || index + length > capacity()) { throw new IndexOutOfBoundsException(); } int endIndex = indexOf(index, index + length, indexFinder); if (endIndex < 0) { return -1; } return endIndex - index; } @Override public int hashCode() { return ChannelBuffers.hashCode(this); } @Override public boolean equals(Object o) { if (!(o instanceof ChannelBuffer)) { return false; } return ChannelBuffers.equals(this, (ChannelBuffer) o); } public int compareTo(ChannelBuffer that) { return ChannelBuffers.compare(this, that); } @Override public String toString() { return getClass().getSimpleName() + '(' + "ridx=" + readerIndex + ", " + "widx=" + writerIndex + ", " + "cap=" + capacity() + ')'; } /** * Throws an {@link IndexOutOfBoundsException} if the current * {@linkplain #readableBytes() readable bytes} of this buffer is less * than the specified value. */ protected void checkReadableBytes(int minimumReadableBytes) { if (readableBytes() < minimumReadableBytes) { throw new IndexOutOfBoundsException("Not enough readable bytes - Need " + minimumReadableBytes + ", maximum is " + readableBytes()); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/AbstractChannelBufferFactory.java000066400000000000000000000034561225554127700324410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.nio.ByteOrder; /** * A skeletal implementation of {@link ChannelBufferFactory}. */ public abstract class AbstractChannelBufferFactory implements ChannelBufferFactory { private final ByteOrder defaultOrder; /** * Creates a new factory whose default {@link ByteOrder} is * {@link ByteOrder#BIG_ENDIAN}. */ protected AbstractChannelBufferFactory() { this(ByteOrder.BIG_ENDIAN); } /** * Creates a new factory with the specified default {@link ByteOrder}. * * @param defaultOrder the default {@link ByteOrder} of this factory */ protected AbstractChannelBufferFactory(ByteOrder defaultOrder) { if (defaultOrder == null) { throw new NullPointerException("defaultOrder"); } this.defaultOrder = defaultOrder; } public ChannelBuffer getBuffer(int capacity) { return getBuffer(getDefaultOrder(), capacity); } public ChannelBuffer getBuffer(byte[] array, int offset, int length) { return getBuffer(getDefaultOrder(), array, offset, length); } public ByteOrder getDefaultOrder() { return defaultOrder; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/BigEndianHeapChannelBuffer.java000066400000000000000000000105361225554127700317610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.nio.ByteOrder; /** * A big-endian Java heap buffer. It is recommended to use {@link ChannelBuffers#buffer(int)} * and {@link ChannelBuffers#wrappedBuffer(byte[])} instead of calling the * constructor explicitly. */ public class BigEndianHeapChannelBuffer extends HeapChannelBuffer { /** * Creates a new big-endian heap buffer with a newly allocated byte array. * * @param length the length of the new byte array */ public BigEndianHeapChannelBuffer(int length) { super(length); } /** * Creates a new big-endian heap buffer with an existing byte array. * * @param array the byte array to wrap */ public BigEndianHeapChannelBuffer(byte[] array) { super(array); } private BigEndianHeapChannelBuffer(byte[] array, int readerIndex, int writerIndex) { super(array, readerIndex, writerIndex); } public ChannelBufferFactory factory() { return HeapChannelBufferFactory.getInstance(ByteOrder.BIG_ENDIAN); } public ByteOrder order() { return ByteOrder.BIG_ENDIAN; } public short getShort(int index) { return (short) (array[index] << 8 | array[index + 1] & 0xFF); } public int getUnsignedMedium(int index) { return (array[index] & 0xff) << 16 | (array[index + 1] & 0xff) << 8 | array[index + 2] & 0xff; } public int getInt(int index) { return (array[index] & 0xff) << 24 | (array[index + 1] & 0xff) << 16 | (array[index + 2] & 0xff) << 8 | array[index + 3] & 0xff; } public long getLong(int index) { return ((long) array[index] & 0xff) << 56 | ((long) array[index + 1] & 0xff) << 48 | ((long) array[index + 2] & 0xff) << 40 | ((long) array[index + 3] & 0xff) << 32 | ((long) array[index + 4] & 0xff) << 24 | ((long) array[index + 5] & 0xff) << 16 | ((long) array[index + 6] & 0xff) << 8 | (long) array[index + 7] & 0xff; } public void setShort(int index, int value) { array[index] = (byte) (value >>> 8); array[index + 1] = (byte) value; } public void setMedium(int index, int value) { array[index] = (byte) (value >>> 16); array[index + 1] = (byte) (value >>> 8); array[index + 2] = (byte) value; } public void setInt(int index, int value) { array[index] = (byte) (value >>> 24); array[index + 1] = (byte) (value >>> 16); array[index + 2] = (byte) (value >>> 8); array[index + 3] = (byte) value; } public void setLong(int index, long value) { array[index] = (byte) (value >>> 56); array[index + 1] = (byte) (value >>> 48); array[index + 2] = (byte) (value >>> 40); array[index + 3] = (byte) (value >>> 32); array[index + 4] = (byte) (value >>> 24); array[index + 5] = (byte) (value >>> 16); array[index + 6] = (byte) (value >>> 8); array[index + 7] = (byte) value; } public ChannelBuffer duplicate() { return new BigEndianHeapChannelBuffer(array, readerIndex(), writerIndex()); } public ChannelBuffer copy(int index, int length) { if (index < 0 || length < 0 || index + length > array.length) { throw new IndexOutOfBoundsException("Too many bytes to copy - Need " + (index + length) + ", maximum is " + array.length); } byte[] copiedArray = new byte[length]; System.arraycopy(array, index, copiedArray, 0, length); return new BigEndianHeapChannelBuffer(copiedArray); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ByteBufferBackedChannelBuffer.java000066400000000000000000000251121225554127700324660ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.ClosedChannelException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link ChannelBuffers#directBuffer(int)} * and {@link ChannelBuffers#wrappedBuffer(ByteBuffer)} instead of calling the * constructor explicitly. */ public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer { private final ByteBuffer buffer; private final ByteOrder order; private final int capacity; /** * Creates a new buffer which wraps the specified buffer's slice. */ public ByteBufferBackedChannelBuffer(ByteBuffer buffer) { if (buffer == null) { throw new NullPointerException("buffer"); } order = buffer.order(); this.buffer = buffer.slice().order(order); capacity = buffer.remaining(); writerIndex(capacity); } private ByteBufferBackedChannelBuffer(ByteBufferBackedChannelBuffer buffer) { this.buffer = buffer.buffer; order = buffer.order; capacity = buffer.capacity; setIndex(buffer.readerIndex(), buffer.writerIndex()); } public ChannelBufferFactory factory() { if (buffer.isDirect()) { return DirectChannelBufferFactory.getInstance(order()); } else { return HeapChannelBufferFactory.getInstance(order()); } } public boolean isDirect() { return buffer.isDirect(); } public ByteOrder order() { return order; } public int capacity() { return capacity; } public boolean hasArray() { return buffer.hasArray(); } public byte[] array() { return buffer.array(); } public int arrayOffset() { return buffer.arrayOffset(); } public byte getByte(int index) { return buffer.get(index); } public short getShort(int index) { return buffer.getShort(index); } public int getUnsignedMedium(int index) { return (getByte(index) & 0xff) << 16 | (getByte(index + 1) & 0xff) << 8 | getByte(index + 2) & 0xff; } public int getInt(int index) { return buffer.getInt(index); } public long getLong(int index) { return buffer.getLong(index); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { if (dst instanceof ByteBufferBackedChannelBuffer) { ByteBufferBackedChannelBuffer bbdst = (ByteBufferBackedChannelBuffer) dst; ByteBuffer data = bbdst.buffer.duplicate(); data.limit(dstIndex + length).position(dstIndex); getBytes(index, data); } else if (buffer.hasArray()) { dst.setBytes(dstIndex, buffer.array(), index + buffer.arrayOffset(), length); } else { dst.setBytes(dstIndex, this, index, length); } } public void getBytes(int index, byte[] dst, int dstIndex, int length) { ByteBuffer data = buffer.duplicate(); try { data.limit(index + length).position(index); } catch (IllegalArgumentException e) { throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length) + ", maximum is " + data.limit()); } data.get(dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { ByteBuffer data = buffer.duplicate(); int bytesToCopy = Math.min(capacity() - index, dst.remaining()); try { data.limit(index + bytesToCopy).position(index); } catch (IllegalArgumentException e) { throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + bytesToCopy) + ", maximum is " + data.limit()); } dst.put(data); } public void setByte(int index, int value) { buffer.put(index, (byte) value); } public void setShort(int index, int value) { buffer.putShort(index, (short) value); } public void setMedium(int index, int value) { setByte(index, (byte) (value >>> 16)); setByte(index + 1, (byte) (value >>> 8)); setByte(index + 2, (byte) value); } public void setInt(int index, int value) { buffer.putInt(index, value); } public void setLong(int index, long value) { buffer.putLong(index, value); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { if (src instanceof ByteBufferBackedChannelBuffer) { ByteBufferBackedChannelBuffer bbsrc = (ByteBufferBackedChannelBuffer) src; ByteBuffer data = bbsrc.buffer.duplicate(); data.limit(srcIndex + length).position(srcIndex); setBytes(index, data); } else if (buffer.hasArray()) { src.getBytes(srcIndex, buffer.array(), index + buffer.arrayOffset(), length); } else { src.getBytes(srcIndex, this, index, length); } } public void setBytes(int index, byte[] src, int srcIndex, int length) { ByteBuffer data = buffer.duplicate(); data.limit(index + length).position(index); data.put(src, srcIndex, length); } public void setBytes(int index, ByteBuffer src) { ByteBuffer data = buffer.duplicate(); data.limit(index + src.remaining()).position(index); data.put(src); } public void getBytes(int index, OutputStream out, int length) throws IOException { if (length == 0) { return; } if (buffer.hasArray()) { out.write( buffer.array(), index + buffer.arrayOffset(), length); } else { byte[] tmp = new byte[length]; ((ByteBuffer) buffer.duplicate().position(index)).get(tmp); out.write(tmp); } } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { if (length == 0) { return 0; } return out.write((ByteBuffer) buffer.duplicate().position(index).limit(index + length)); } public int setBytes(int index, InputStream in, int length) throws IOException { int readBytes = 0; if (buffer.hasArray()) { index += buffer.arrayOffset(); do { int localReadBytes = in.read(buffer.array(), index, length); if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } readBytes += localReadBytes; index += localReadBytes; length -= localReadBytes; } while (length > 0); } else { byte[] tmp = new byte[length]; int i = 0; do { int localReadBytes = in.read(tmp, i, tmp.length - i); if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } readBytes += localReadBytes; i += readBytes; } while (i < tmp.length); ((ByteBuffer) buffer.duplicate().position(index)).put(tmp); } return readBytes; } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { ByteBuffer slice = (ByteBuffer) buffer.duplicate().limit(index + length).position(index); int readBytes = 0; while (readBytes < length) { int localReadBytes; try { localReadBytes = in.read(slice); } catch (ClosedChannelException e) { localReadBytes = -1; } if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { return readBytes; } } if (localReadBytes == 0) { break; } readBytes += localReadBytes; } return readBytes; } public ByteBuffer toByteBuffer(int index, int length) { if (index == 0 && length == capacity()) { return buffer.duplicate().order(order()); } else { return ((ByteBuffer) buffer.duplicate().position( index).limit(index + length)).slice().order(order()); } } public ChannelBuffer slice(int index, int length) { if (index == 0 && length == capacity()) { ChannelBuffer slice = duplicate(); slice.setIndex(0, length); return slice; } else { if (index >= 0 && length == 0) { return ChannelBuffers.EMPTY_BUFFER; } return new ByteBufferBackedChannelBuffer( ((ByteBuffer) buffer.duplicate().position( index).limit(index + length)).order(order())); } } public ChannelBuffer duplicate() { return new ByteBufferBackedChannelBuffer(this); } public ChannelBuffer copy(int index, int length) { ByteBuffer src; try { src = (ByteBuffer) buffer.duplicate().position(index).limit(index + length); } catch (IllegalArgumentException e) { throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length)); } ByteBuffer dst = buffer.isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length); dst.put(src); dst.order(order()); dst.clear(); return new ByteBufferBackedChannelBuffer(dst); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ChannelBuffer.java000066400000000000000000002134221225554127700274210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; /** * A random and sequential accessible sequence of zero or more bytes (octets). * This interface provides an abstract view for one or more primitive byte * arrays ({@code byte[]}) and {@linkplain ByteBuffer NIO buffers}. * *

Creation of a buffer

* * It is recommended to create a new buffer using the helper methods in * {@link ChannelBuffers} rather than calling an individual implementation's * constructor. * *

Random Access Indexing

* * Just like an ordinary primitive byte array, {@link ChannelBuffer} uses * zero-based indexing. * It means the index of the first byte is always {@code 0} and the index of the last byte is * always {@link #capacity() capacity - 1}. For example, to iterate all bytes of a buffer, you * can do the following, regardless of its internal implementation: * *
 * {@link ChannelBuffer} buffer = ...;
 * for (int i = 0; i < buffer.capacity(); i ++) {
 *     byte b = buffer.getByte(i);
 *     System.out.println((char) b);
 * }
 * 
* *

Sequential Access Indexing

* * {@link ChannelBuffer} provides two pointer variables to support sequential * read and write operations - {@link #readerIndex() readerIndex} for a read * operation and {@link #writerIndex() writerIndex} for a write operation * respectively. The following diagram shows how a buffer is segmented into * three areas by the two pointers: * *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 * 
* *

Readable bytes (the actual content)

* * This segment is where the actual data is stored. Any operation whose name * starts with {@code read} or {@code skip} will get or skip the data at the * current {@link #readerIndex() readerIndex} and increase it by the number of * read bytes. If the argument of the read operation is also a * {@link ChannelBuffer} and no destination index is specified, the specified * buffer's {@link #readerIndex() readerIndex} is increased together. *

* If there's not enough content left, {@link IndexOutOfBoundsException} is * raised. The default value of newly allocated, wrapped or copied buffer's * {@link #readerIndex() readerIndex} is {@code 0}. * *

 * // Iterates the readable bytes of a buffer.
 * {@link ChannelBuffer} buffer = ...;
 * while (buffer.readable()) {
 *     System.out.println(buffer.readByte());
 * }
 * 
* *

Writable bytes

* * This segment is a undefined space which needs to be filled. Any operation * whose name ends with {@code write} will write the data at the current * {@link #writerIndex() writerIndex} and increase it by the number of written * bytes. If the argument of the write operation is also a {@link ChannelBuffer}, * and no source index is specified, the specified buffer's * {@link #readerIndex() readerIndex} is increased together. *

* If there's not enough writable bytes left, {@link IndexOutOfBoundsException} * is raised. The default value of newly allocated buffer's * {@link #writerIndex() writerIndex} is {@code 0}. The default value of * wrapped or copied buffer's {@link #writerIndex() writerIndex} is the * {@link #capacity() capacity} of the buffer. * *

 * // Fills the writable bytes of a buffer with random integers.
 * {@link ChannelBuffer} buffer = ...;
 * while (buffer.writableBytes() >= 4) {
 *     buffer.writeInt(random.nextInt());
 * }
 * 
* *

Discardable bytes

* * This segment contains the bytes which were read already by a read operation. * Initially, the size of this segment is {@code 0}, but its size increases up * to the {@link #writerIndex() writerIndex} as read operations are executed. * The read bytes can be discarded by calling {@link #discardReadBytes()} to * reclaim unused area as depicted by the following diagram: * *
 *  BEFORE discardReadBytes()
 *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 *
 *
 *  AFTER discardReadBytes()
 *
 *      +------------------+--------------------------------------+
 *      |  readable bytes  |    writable bytes (got more space)   |
 *      +------------------+--------------------------------------+
 *      |                  |                                      |
 * readerIndex (0) <= writerIndex (decreased)        <=        capacity
 * 
* * Please note that there is no guarantee about the content of writable bytes * after calling {@link #discardReadBytes()}. The writable bytes will not be * moved in most cases and could even be filled with completely different data * depending on the underlying buffer implementation. * *

Clearing the buffer indexes

* * You can set both {@link #readerIndex() readerIndex} and * {@link #writerIndex() writerIndex} to {@code 0} by calling {@link #clear()}. * It does not clear the buffer content (e.g. filling with {@code 0}) but just * clears the two pointers. Please also note that the semantic of this * operation is different from {@link ByteBuffer#clear()}. * *
 *  BEFORE clear()
 *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 *
 *
 *  AFTER clear()
 *
 *      +---------------------------------------------------------+
 *      |             writable bytes (got more space)             |
 *      +---------------------------------------------------------+
 *      |                                                         |
 *      0 = readerIndex = writerIndex            <=            capacity
 * 
* *

Search operations

* * Various {@link #indexOf(int, int, byte)} methods help you locate an index of * a value which meets a certain criteria. Complicated dynamic sequential * search can be done with {@link ChannelBufferIndexFinder} as well as simple * static single byte search. *

* If you are decoding variable length data such as NUL-terminated string, you * will find {@link #bytesBefore(byte)} also useful. * *

Mark and reset

* * There are two marker indexes in every buffer. One is for storing * {@link #readerIndex() readerIndex} and the other is for storing * {@link #writerIndex() writerIndex}. You can always reposition one of the * two indexes by calling a reset method. It works in a similar fashion to * the mark and reset methods in {@link InputStream} except that there's no * {@code readlimit}. * *

Derived buffers

* * You can create a view of an existing buffer by calling either * {@link #duplicate()}, {@link #slice()} or {@link #slice(int, int)}. * A derived buffer will have an independent {@link #readerIndex() readerIndex}, * {@link #writerIndex() writerIndex} and marker indexes, while it shares * other internal data representation, just like a NIO buffer does. *

* In case a completely fresh copy of an existing buffer is required, please * call {@link #copy()} method instead. * *

Conversion to existing JDK types

* *

Byte array

* * If a {@link ChannelBuffer} is backed by a byte array (i.e. {@code byte[]}), * you can access it directly via the {@link #array()} method. To determine * if a buffer is backed by a byte array, {@link #hasArray()} should be used. * *

NIO Buffers

* * Various {@link #toByteBuffer()} and {@link #toByteBuffers()} methods convert * a {@link ChannelBuffer} into one or more NIO buffers. These methods avoid * buffer allocation and memory copy whenever possible, but there's no * guarantee that memory copy will not be involved. * *

Strings

* * Various {@link #toString(String)} methods convert a {@link ChannelBuffer} * into a {@link String}. Please note that {@link #toString()} is not a * conversion method. * *

I/O Streams

* * Please refer to {@link ChannelBufferInputStream} and * {@link ChannelBufferOutputStream}. * * @apiviz.landmark */ public interface ChannelBuffer extends Comparable { /** * Returns the factory which creates a {@link ChannelBuffer} whose * type and default {@link ByteOrder} are same with this buffer. */ ChannelBufferFactory factory(); /** * Returns the number of bytes (octets) this buffer can contain. */ int capacity(); /** * Returns the endianness * of this buffer. */ ByteOrder order(); /** * Returns {@code true} if and only if this buffer is backed by an * NIO direct buffer. */ boolean isDirect(); /** * Returns the {@code readerIndex} of this buffer. */ int readerIndex(); /** * Sets the {@code readerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code readerIndex} is * less than {@code 0} or * greater than {@code this.writerIndex} */ void readerIndex(int readerIndex); /** * Returns the {@code writerIndex} of this buffer. */ int writerIndex(); /** * Sets the {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code writerIndex} is * less than {@code this.readerIndex} or * greater than {@code this.capacity} */ void writerIndex(int writerIndex); /** * Sets the {@code readerIndex} and {@code writerIndex} of this buffer * in one shot. This method is useful when you have to worry about the * invocation order of {@link #readerIndex(int)} and {@link #writerIndex(int)} * methods. For example, the following code will fail: * *
     * // Create a buffer whose readerIndex, writerIndex and capacity are
     * // 0, 0 and 8 respectively.
     * {@link ChannelBuffer} buf = {@link ChannelBuffers}.buffer(8);
     *
     * // IndexOutOfBoundsException is thrown because the specified
     * // readerIndex (2) cannot be greater than the current writerIndex (0).
     * buf.readerIndex(2);
     * buf.writerIndex(4);
     * 
* * The following code will also fail: * *
     * // Create a buffer whose readerIndex, writerIndex and capacity are
     * // 0, 8 and 8 respectively.
     * {@link ChannelBuffer} buf = {@link ChannelBuffers}.wrappedBuffer(new byte[8]);
     *
     * // readerIndex becomes 8.
     * buf.readLong();
     *
     * // IndexOutOfBoundsException is thrown because the specified
     * // writerIndex (4) cannot be less than the current readerIndex (8).
     * buf.writerIndex(4);
     * buf.readerIndex(2);
     * 
* * By contrast, this method guarantees that it never * throws an {@link IndexOutOfBoundsException} as long as the specified * indexes meet basic constraints, regardless what the current index * values of the buffer are: * *
     * // No matter what the current state of the buffer is, the following
     * // call always succeeds as long as the capacity of the buffer is not
     * // less than 4.
     * buf.setIndex(2, 4);
     * 
* * @throws IndexOutOfBoundsException * if the specified {@code readerIndex} is less than 0, * if the specified {@code writerIndex} is less than the specified * {@code readerIndex} or if the specified {@code writerIndex} is * greater than {@code this.capacity} */ void setIndex(int readerIndex, int writerIndex); /** * Returns the number of readable bytes which is equal to * {@code (this.writerIndex - this.readerIndex)}. */ int readableBytes(); /** * Returns the number of writable bytes which is equal to * {@code (this.capacity - this.writerIndex)}. */ int writableBytes(); /** * Returns {@code true} * if and only if {@code (this.writerIndex - this.readerIndex)} is greater * than {@code 0}. */ boolean readable(); /** * Returns {@code true} * if and only if {@code (this.capacity - this.writerIndex)} is greater * than {@code 0}. */ boolean writable(); /** * Sets the {@code readerIndex} and {@code writerIndex} of this buffer to * {@code 0}. * This method is identical to {@link #setIndex(int, int) setIndex(0, 0)}. *

* Please note that the behavior of this method is different * from that of NIO buffer, which sets the {@code limit} to * the {@code capacity} of the buffer. */ void clear(); /** * Marks the current {@code readerIndex} in this buffer. You can * reposition the current {@code readerIndex} to the marked * {@code readerIndex} by calling {@link #resetReaderIndex()}. * The initial value of the marked {@code readerIndex} is {@code 0}. */ void markReaderIndex(); /** * Repositions the current {@code readerIndex} to the marked * {@code readerIndex} in this buffer. * * @throws IndexOutOfBoundsException * if the current {@code writerIndex} is less than the marked * {@code readerIndex} */ void resetReaderIndex(); /** * Marks the current {@code writerIndex} in this buffer. You can * reposition the current {@code writerIndex} to the marked * {@code writerIndex} by calling {@link #resetWriterIndex()}. * The initial value of the marked {@code writerIndex} is {@code 0}. */ void markWriterIndex(); /** * Repositions the current {@code writerIndex} to the marked * {@code writerIndex} in this buffer. * * @throws IndexOutOfBoundsException * if the current {@code readerIndex} is greater than the marked * {@code writerIndex} */ void resetWriterIndex(); /** * Discards the bytes between the 0th index and {@code readerIndex}. * It moves the bytes between {@code readerIndex} and {@code writerIndex} * to the 0th index, and sets {@code readerIndex} and {@code writerIndex} * to {@code 0} and {@code oldWriterIndex - oldReaderIndex} respectively. *

* Please refer to the class documentation for more detailed explanation. */ void discardReadBytes(); /** * Makes sure the number of {@linkplain #writableBytes() the writable bytes} * is equal to or greater than the specified value. If there is enough * writable bytes in this buffer, this method returns with no side effect. * Otherwise: *

    *
  • a non-dynamic buffer will throw an {@link IndexOutOfBoundsException}.
  • *
  • a dynamic buffer will expand its capacity so that the number of the * {@link #writableBytes() writable bytes} becomes equal to or greater * than the specified value. The expansion involves the reallocation of * the internal buffer and consequently memory copy.
  • *
* * @param writableBytes * the expected minimum number of writable bytes * @throws IndexOutOfBoundsException * if {@linkplain #writableBytes() the writable bytes} of this * buffer is less than the specified value and if this buffer is * not a dynamic buffer */ void ensureWritableBytes(int writableBytes); /** * Gets a byte at the specified absolute {@code index} in this buffer. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 1} is greater than {@code this.capacity} */ byte getByte(int index); /** * Gets an unsigned byte at the specified absolute {@code index} in this * buffer. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 1} is greater than {@code this.capacity} */ short getUnsignedByte(int index); /** * Gets a 16-bit short integer at the specified absolute {@code index} in * this buffer. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.capacity} */ short getShort(int index); /** * Gets an unsigned 16-bit short integer at the specified absolute * {@code index} in this buffer. This method does not modify * {@code readerIndex} or {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.capacity} */ int getUnsignedShort(int index); /** * Gets a 24-bit medium integer at the specified absolute {@code index} in * this buffer. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 3} is greater than {@code this.capacity} */ int getMedium(int index); /** * Gets an unsigned 24-bit medium integer at the specified absolute * {@code index} in this buffer. This method does not modify * {@code readerIndex} or {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 3} is greater than {@code this.capacity} */ int getUnsignedMedium(int index); /** * Gets a 32-bit integer at the specified absolute {@code index} in * this buffer. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.capacity} */ int getInt(int index); /** * Gets an unsigned 32-bit integer at the specified absolute {@code index} * in this buffer. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.capacity} */ long getUnsignedInt(int index); /** * Gets a 64-bit long integer at the specified absolute {@code index} in * this buffer. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.capacity} */ long getLong(int index); /** * Gets a 2-byte UTF-16 character at the specified absolute * {@code index} in this buffer. This method does not modify * {@code readerIndex} or {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.capacity} */ char getChar(int index); /** * Gets a 32-bit floating point number at the specified absolute * {@code index} in this buffer. This method does not modify * {@code readerIndex} or {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.capacity} */ float getFloat(int index); /** * Gets a 64-bit floating point number at the specified absolute * {@code index} in this buffer. This method does not modify * {@code readerIndex} or {@code writerIndex} of this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.capacity} */ double getDouble(int index); /** * Transfers this buffer's data to the specified destination starting at * the specified absolute {@code index} until the destination becomes * non-writable. This method is basically same with * {@link #getBytes(int, ChannelBuffer, int, int)}, except that this * method increases the {@code writerIndex} of the destination by the * number of the transferred bytes while * {@link #getBytes(int, ChannelBuffer, int, int)} does not. * This method does not modify {@code readerIndex} or {@code writerIndex} of * the source buffer (i.e. {@code this}). * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + dst.writableBytes} is greater than * {@code this.capacity} */ void getBytes(int index, ChannelBuffer dst); /** * Transfers this buffer's data to the specified destination starting at * the specified absolute {@code index}. This method is basically same * with {@link #getBytes(int, ChannelBuffer, int, int)}, except that this * method increases the {@code writerIndex} of the destination by the * number of the transferred bytes while * {@link #getBytes(int, ChannelBuffer, int, int)} does not. * This method does not modify {@code readerIndex} or {@code writerIndex} of * the source buffer (i.e. {@code this}). * * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.capacity}, or * if {@code length} is greater than {@code dst.writableBytes} */ void getBytes(int index, ChannelBuffer dst, int length); /** * Transfers this buffer's data to the specified destination starting at * the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} * of both the source (i.e. {@code this}) and the destination. * * @param dstIndex the first index of the destination * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0}, * if the specified {@code dstIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.capacity}, or * if {@code dstIndex + length} is greater than * {@code dst.capacity} */ void getBytes(int index, ChannelBuffer dst, int dstIndex, int length); /** * Transfers this buffer's data to the specified destination starting at * the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + dst.length} is greater than * {@code this.capacity} */ void getBytes(int index, byte[] dst); /** * Transfers this buffer's data to the specified destination starting at * the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} * of this buffer. * * @param dstIndex the first index of the destination * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0}, * if the specified {@code dstIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.capacity}, or * if {@code dstIndex + length} is greater than * {@code dst.length} */ void getBytes(int index, byte[] dst, int dstIndex, int length); /** * Transfers this buffer's data to the specified destination starting at * the specified absolute {@code index} until the destination's position * reaches its limit. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer while the destination's {@code position} will be increased. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + dst.remaining()} is greater than * {@code this.capacity} */ void getBytes(int index, ByteBuffer dst); /** * Transfers this buffer's data to the specified stream starting at the * specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + length} is greater than * {@code this.capacity} * @throws IOException * if the specified stream threw an exception during I/O */ void getBytes(int index, OutputStream out, int length) throws IOException; /** * Transfers this buffer's data to the specified channel starting at the * specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @param length the maximum number of bytes to transfer * * @return the actual number of bytes written out to the specified channel * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + length} is greater than * {@code this.capacity} * @throws IOException * if the specified channel threw an exception during I/O */ int getBytes(int index, GatheringByteChannel out, int length) throws IOException; /** * Sets the specified byte at the specified absolute {@code index} in this * buffer. The 24 high-order bits of the specified value are ignored. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 1} is greater than {@code this.capacity} */ void setByte(int index, int value); /** * Sets the specified 16-bit short integer at the specified absolute * {@code index} in this buffer. The 16 high-order bits of the specified * value are ignored. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.capacity} */ void setShort(int index, int value); /** * Sets the specified 24-bit medium integer at the specified absolute * {@code index} in this buffer. Please note that the most significant * byte is ignored in the specified value. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 3} is greater than {@code this.capacity} */ void setMedium(int index, int value); /** * Sets the specified 32-bit integer at the specified absolute * {@code index} in this buffer. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.capacity} */ void setInt(int index, int value); /** * Sets the specified 64-bit long integer at the specified absolute * {@code index} in this buffer. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.capacity} */ void setLong(int index, long value); /** * Sets the specified 2-byte UTF-16 character at the specified absolute * {@code index} in this buffer. * The 16 high-order bits of the specified value are ignored. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 2} is greater than {@code this.capacity} */ void setChar(int index, int value); /** * Sets the specified 32-bit floating-point number at the specified * absolute {@code index} in this buffer. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 4} is greater than {@code this.capacity} */ void setFloat(int index, float value); /** * Sets the specified 64-bit floating-point number at the specified * absolute {@code index} in this buffer. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * {@code index + 8} is greater than {@code this.capacity} */ void setDouble(int index, double value); /** * Transfers the specified source buffer's data to this buffer starting at * the specified absolute {@code index} until the source buffer becomes * unreadable. This method is basically same with * {@link #setBytes(int, ChannelBuffer, int, int)}, except that this * method increases the {@code readerIndex} of the source buffer by * the number of the transferred bytes while * {@link #setBytes(int, ChannelBuffer, int, int)} does not. * This method does not modify {@code readerIndex} or {@code writerIndex} of * the source buffer (i.e. {@code this}). * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + src.readableBytes} is greater than * {@code this.capacity} */ void setBytes(int index, ChannelBuffer src); /** * Transfers the specified source buffer's data to this buffer starting at * the specified absolute {@code index}. This method is basically same * with {@link #setBytes(int, ChannelBuffer, int, int)}, except that this * method increases the {@code readerIndex} of the source buffer by * the number of the transferred bytes while * {@link #setBytes(int, ChannelBuffer, int, int)} does not. * This method does not modify {@code readerIndex} or {@code writerIndex} of * the source buffer (i.e. {@code this}). * * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.capacity}, or * if {@code length} is greater than {@code src.readableBytes} */ void setBytes(int index, ChannelBuffer src, int length); /** * Transfers the specified source buffer's data to this buffer starting at * the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} * of both the source (i.e. {@code this}) and the destination. * * @param srcIndex the first index of the source * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0}, * if the specified {@code srcIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.capacity}, or * if {@code srcIndex + length} is greater than * {@code src.capacity} */ void setBytes(int index, ChannelBuffer src, int srcIndex, int length); /** * Transfers the specified source array's data to this buffer starting at * the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + src.length} is greater than * {@code this.capacity} */ void setBytes(int index, byte[] src); /** * Transfers the specified source array's data to this buffer starting at * the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0}, * if the specified {@code srcIndex} is less than {@code 0}, * if {@code index + length} is greater than * {@code this.capacity}, or * if {@code srcIndex + length} is greater than {@code src.length} */ void setBytes(int index, byte[] src, int srcIndex, int length); /** * Transfers the specified source buffer's data to this buffer starting at * the specified absolute {@code index} until the source buffer's position * reaches its limit. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + src.remaining()} is greater than * {@code this.capacity} */ void setBytes(int index, ByteBuffer src); /** * Transfers the content of the specified source stream to this buffer * starting at the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @param length the number of bytes to transfer * * @return the actual number of bytes read in from the specified channel. * {@code -1} if the specified channel is closed. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + length} is greater than {@code this.capacity} * @throws IOException * if the specified stream threw an exception during I/O */ int setBytes(int index, InputStream in, int length) throws IOException; /** * Transfers the content of the specified source channel to this buffer * starting at the specified absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @param length the maximum number of bytes to transfer * * @return the actual number of bytes read in from the specified channel. * {@code -1} if the specified channel is closed. * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + length} is greater than {@code this.capacity} * @throws IOException * if the specified channel threw an exception during I/O */ int setBytes(int index, ScatteringByteChannel in, int length) throws IOException; /** * Fills this buffer with NUL (0x00) starting at the specified * absolute {@code index}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @param length the number of NULs to write to the buffer * * @throws IndexOutOfBoundsException * if the specified {@code index} is less than {@code 0} or * if {@code index + length} is greater than {@code this.capacity} */ void setZero(int index, int length); /** * Gets a byte at the current {@code readerIndex} and increases * the {@code readerIndex} by {@code 1} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 1} */ byte readByte(); /** * Gets an unsigned byte at the current {@code readerIndex} and increases * the {@code readerIndex} by {@code 1} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 1} */ short readUnsignedByte(); /** * Gets a 16-bit short integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 2} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 2} */ short readShort(); /** * Gets an unsigned 16-bit short integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 2} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 2} */ int readUnsignedShort(); /** * Gets a 24-bit medium integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 3} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 3} */ int readMedium(); /** * Gets an unsigned 24-bit medium integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 3} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 3} */ int readUnsignedMedium(); /** * Gets a 32-bit integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 4} */ int readInt(); /** * Gets an unsigned 32-bit integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 4} */ long readUnsignedInt(); /** * Gets a 64-bit integer at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 8} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 8} */ long readLong(); /** * Gets a 2-byte UTF-16 character at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 2} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 2} */ char readChar(); /** * Gets a 32-bit floating point number at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 4} */ float readFloat(); /** * Gets a 64-bit floating point number at the current {@code readerIndex} * and increases the {@code readerIndex} by {@code 8} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.readableBytes} is less than {@code 8} */ double readDouble(); /** * Transfers this buffer's data to a newly created buffer starting at * the current {@code readerIndex} and increases the {@code readerIndex} * by the number of the transferred bytes (= {@code length}). * The returned buffer's {@code readerIndex} and {@code writerIndex} are * {@code 0} and {@code length} respectively. * * @param length the number of bytes to transfer * * @return the newly created buffer which contains the transferred bytes * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} */ ChannelBuffer readBytes(int length); /** * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #readBytes(int)} instead. */ @Deprecated ChannelBuffer readBytes(ChannelBufferIndexFinder indexFinder); /** * Returns a new slice of this buffer's sub-region starting at the current * {@code readerIndex} and increases the {@code readerIndex} by the size * of the new slice (= {@code length}). * * @param length the size of the new slice * * @return the newly created slice * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} */ ChannelBuffer readSlice(int length); /** * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #readSlice(int)} instead. */ @Deprecated ChannelBuffer readSlice(ChannelBufferIndexFinder indexFinder); /** * Transfers this buffer's data to the specified destination starting at * the current {@code readerIndex} until the destination becomes * non-writable, and increases the {@code readerIndex} by the number of the * transferred bytes. This method is basically same with * {@link #readBytes(ChannelBuffer, int, int)}, except that this method * increases the {@code writerIndex} of the destination by the number of * the transferred bytes while {@link #readBytes(ChannelBuffer, int, int)} * does not. * * @throws IndexOutOfBoundsException * if {@code dst.writableBytes} is greater than * {@code this.readableBytes} */ void readBytes(ChannelBuffer dst); /** * Transfers this buffer's data to the specified destination starting at * the current {@code readerIndex} and increases the {@code readerIndex} * by the number of the transferred bytes (= {@code length}). This method * is basically same with {@link #readBytes(ChannelBuffer, int, int)}, * except that this method increases the {@code writerIndex} of the * destination by the number of the transferred bytes (= {@code length}) * while {@link #readBytes(ChannelBuffer, int, int)} does not. * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} or * if {@code length} is greater than {@code dst.writableBytes} */ void readBytes(ChannelBuffer dst, int length); /** * Transfers this buffer's data to the specified destination starting at * the current {@code readerIndex} and increases the {@code readerIndex} * by the number of the transferred bytes (= {@code length}). * * @param dstIndex the first index of the destination * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code dstIndex} is less than {@code 0}, * if {@code length} is greater than {@code this.readableBytes}, or * if {@code dstIndex + length} is greater than * {@code dst.capacity} */ void readBytes(ChannelBuffer dst, int dstIndex, int length); /** * Transfers this buffer's data to the specified destination starting at * the current {@code readerIndex} and increases the {@code readerIndex} * by the number of the transferred bytes (= {@code dst.length}). * * @throws IndexOutOfBoundsException * if {@code dst.length} is greater than {@code this.readableBytes} */ void readBytes(byte[] dst); /** * Transfers this buffer's data to the specified destination starting at * the current {@code readerIndex} and increases the {@code readerIndex} * by the number of the transferred bytes (= {@code length}). * * @param dstIndex the first index of the destination * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code dstIndex} is less than {@code 0}, * if {@code length} is greater than {@code this.readableBytes}, or * if {@code dstIndex + length} is greater than {@code dst.length} */ void readBytes(byte[] dst, int dstIndex, int length); /** * Transfers this buffer's data to the specified destination starting at * the current {@code readerIndex} until the destination's position * reaches its limit, and increases the {@code readerIndex} by the * number of the transferred bytes. * * @throws IndexOutOfBoundsException * if {@code dst.remaining()} is greater than * {@code this.readableBytes} */ void readBytes(ByteBuffer dst); /** * Transfers this buffer's data to the specified stream starting at the * current {@code readerIndex}. * * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} * @throws IOException * if the specified stream threw an exception during I/O */ void readBytes(OutputStream out, int length) throws IOException; /** * Transfers this buffer's data to the specified stream starting at the * current {@code readerIndex}. * * @param length the maximum number of bytes to transfer * * @return the actual number of bytes written out to the specified channel * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} * @throws IOException * if the specified channel threw an exception during I/O */ int readBytes(GatheringByteChannel out, int length) throws IOException; /** * Increases the current {@code readerIndex} by the specified * {@code length} in this buffer. * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} */ void skipBytes(int length); /** * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #skipBytes(int)} instead. */ @Deprecated int skipBytes(ChannelBufferIndexFinder indexFinder); /** * Sets the specified byte at the current {@code writerIndex} * and increases the {@code writerIndex} by {@code 1} in this buffer. * The 24 high-order bits of the specified value are ignored. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 1} */ void writeByte(int value); /** * Sets the specified 16-bit short integer at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 2} * in this buffer. The 16 high-order bits of the specified value are ignored. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 2} */ void writeShort(int value); /** * Sets the specified 24-bit medium integer at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 3} * in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 3} */ void writeMedium(int value); /** * Sets the specified 32-bit integer at the current {@code writerIndex} * and increases the {@code writerIndex} by {@code 4} in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 4} */ void writeInt(int value); /** * Sets the specified 64-bit long integer at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 8} * in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 8} */ void writeLong(long value); /** * Sets the specified 2-byte UTF-16 character at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 2} * in this buffer. The 16 high-order bits of the specified value are ignored. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 2} */ void writeChar(int value); /** * Sets the specified 32-bit floating point number at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 4} * in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 4} */ void writeFloat(float value); /** * Sets the specified 64-bit floating point number at the current * {@code writerIndex} and increases the {@code writerIndex} by {@code 8} * in this buffer. * * @throws IndexOutOfBoundsException * if {@code this.writableBytes} is less than {@code 8} */ void writeDouble(double value); /** * Transfers the specified source buffer's data to this buffer starting at * the current {@code writerIndex} until the source buffer becomes * unreadable, and increases the {@code writerIndex} by the number of * the transferred bytes. This method is basically same with * {@link #writeBytes(ChannelBuffer, int, int)}, except that this method * increases the {@code readerIndex} of the source buffer by the number of * the transferred bytes while {@link #writeBytes(ChannelBuffer, int, int)} * does not. * * @throws IndexOutOfBoundsException * if {@code src.readableBytes} is greater than * {@code this.writableBytes} */ void writeBytes(ChannelBuffer src); /** * Transfers the specified source buffer's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code length}). This method * is basically same with {@link #writeBytes(ChannelBuffer, int, int)}, * except that this method increases the {@code readerIndex} of the source * buffer by the number of the transferred bytes (= {@code length}) while * {@link #writeBytes(ChannelBuffer, int, int)} does not. * * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.writableBytes} or * if {@code length} is greater then {@code src.readableBytes} */ void writeBytes(ChannelBuffer src, int length); /** * Transfers the specified source buffer's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code length}). * * @param srcIndex the first index of the source * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code srcIndex} is less than {@code 0}, * if {@code srcIndex + length} is greater than * {@code src.capacity}, or * if {@code length} is greater than {@code this.writableBytes} */ void writeBytes(ChannelBuffer src, int srcIndex, int length); /** * Transfers the specified source array's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code src.length}). * * @throws IndexOutOfBoundsException * if {@code src.length} is greater than {@code this.writableBytes} */ void writeBytes(byte[] src); /** * Transfers the specified source array's data to this buffer starting at * the current {@code writerIndex} and increases the {@code writerIndex} * by the number of the transferred bytes (= {@code length}). * * @param srcIndex the first index of the source * @param length the number of bytes to transfer * * @throws IndexOutOfBoundsException * if the specified {@code srcIndex} is less than {@code 0}, * if {@code srcIndex + length} is greater than * {@code src.length}, or * if {@code length} is greater than {@code this.writableBytes} */ void writeBytes(byte[] src, int srcIndex, int length); /** * Transfers the specified source buffer's data to this buffer starting at * the current {@code writerIndex} until the source buffer's position * reaches its limit, and increases the {@code writerIndex} by the * number of the transferred bytes. * * @throws IndexOutOfBoundsException * if {@code src.remaining()} is greater than * {@code this.writableBytes} */ void writeBytes(ByteBuffer src); /** * Transfers the content of the specified stream to this buffer * starting at the current {@code writerIndex} and increases the * {@code writerIndex} by the number of the transferred bytes. * * @param length the number of bytes to transfer * * @return the actual number of bytes read in from the specified stream * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.writableBytes} * @throws IOException * if the specified stream threw an exception during I/O */ int writeBytes(InputStream in, int length) throws IOException; /** * Transfers the content of the specified channel to this buffer * starting at the current {@code writerIndex} and increases the * {@code writerIndex} by the number of the transferred bytes. * * @param length the maximum number of bytes to transfer * * @return the actual number of bytes read in from the specified channel * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.writableBytes} * @throws IOException * if the specified channel threw an exception during I/O */ int writeBytes(ScatteringByteChannel in, int length) throws IOException; /** * Fills this buffer with NUL (0x00) starting at the current * {@code writerIndex} and increases the {@code writerIndex} by the * specified {@code length}. * * @param length the number of NULs to write to the buffer * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.writableBytes} */ void writeZero(int length); /** * Locates the first occurrence of the specified {@code value} in this * buffer. The search takes place from the specified {@code fromIndex} * (inclusive) to the specified {@code toIndex} (exclusive). *

* If {@code fromIndex} is greater than {@code toIndex}, the search is * performed in a reversed order. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the absolute index of the first occurrence if found. * {@code -1} otherwise. */ int indexOf(int fromIndex, int toIndex, byte value); /** * Locates the first place where the specified {@code indexFinder} * returns {@code true}. The search takes place from the specified * {@code fromIndex} (inclusive) to the specified {@code toIndex} * (exclusive). *

* If {@code fromIndex} is greater than {@code toIndex}, the search is * performed in a reversed order. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the absolute index where the specified {@code indexFinder} * returned {@code true}. {@code -1} if the {@code indexFinder} * did not return {@code true} at all. */ int indexOf(int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder); /** * Locates the first occurrence of the specified {@code value} in this * buffer. The search takes place from the current {@code readerIndex} * (inclusive) to the current {@code writerIndex} (exclusive). *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the number of bytes between the current {@code readerIndex} * and the first occurrence if found. {@code -1} otherwise. */ int bytesBefore(byte value); /** * Locates the first place where the specified {@code indexFinder} returns * {@code true}. The search takes place from the current {@code readerIndex} * (inclusive) to the current {@code writerIndex}. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the number of bytes between the current {@code readerIndex} * and the first place where the {@code indexFinder} returned * {@code true}. {@code -1} if the {@code indexFinder} did not * return {@code true} at all. */ int bytesBefore(ChannelBufferIndexFinder indexFinder); /** * Locates the first occurrence of the specified {@code value} in this * buffer. The search starts from the current {@code readerIndex} * (inclusive) and lasts for the specified {@code length}. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the number of bytes between the current {@code readerIndex} * and the first occurrence if found. {@code -1} otherwise. * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} */ int bytesBefore(int length, byte value); /** * Locates the first place where the specified {@code indexFinder} returns * {@code true}. The search starts the current {@code readerIndex} * (inclusive) and lasts for the specified {@code length}. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the number of bytes between the current {@code readerIndex} * and the first place where the {@code indexFinder} returned * {@code true}. {@code -1} if the {@code indexFinder} did not * return {@code true} at all. * * @throws IndexOutOfBoundsException * if {@code length} is greater than {@code this.readableBytes} */ int bytesBefore(int length, ChannelBufferIndexFinder indexFinder); /** * Locates the first occurrence of the specified {@code value} in this * buffer. The search starts from the specified {@code index} (inclusive) * and lasts for the specified {@code length}. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the number of bytes between the specified {@code index} * and the first occurrence if found. {@code -1} otherwise. * * @throws IndexOutOfBoundsException * if {@code index + length} is greater than {@code this.capacity} */ int bytesBefore(int index, int length, byte value); /** * Locates the first place where the specified {@code indexFinder} returns * {@code true}. The search starts the specified {@code index} (inclusive) * and lasts for the specified {@code length}. *

* This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @return the number of bytes between the specified {@code index} * and the first place where the {@code indexFinder} returned * {@code true}. {@code -1} if the {@code indexFinder} did not * return {@code true} at all. * * @throws IndexOutOfBoundsException * if {@code index + length} is greater than {@code this.capacity} */ int bytesBefore(int index, int length, ChannelBufferIndexFinder indexFinder); /** * Returns a copy of this buffer's readable bytes. Modifying the content * of the returned buffer or this buffer does not affect each other at all. * This method is identical to {@code buf.copy(buf.readerIndex(), buf.readableBytes())}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ChannelBuffer copy(); /** * Returns a copy of this buffer's sub-region. Modifying the content of * the returned buffer or this buffer does not affect each other at all. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ChannelBuffer copy(int index, int length); /** * Returns a slice of this buffer's readable bytes. Modifying the content * of the returned buffer or this buffer affects each other's content * while they maintain separate indexes and marks. This method is * identical to {@code buf.slice(buf.readerIndex(), buf.readableBytes())}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ChannelBuffer slice(); /** * Returns a slice of this buffer's sub-region. Modifying the content of * the returned buffer or this buffer affects each other's content while * they maintain separate indexes and marks. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ChannelBuffer slice(int index, int length); /** * Returns a buffer which shares the whole region of this buffer. * Modifying the content of the returned buffer or this buffer affects * each other's content while they maintain separate indexes and marks. * This method is identical to {@code buf.slice(0, buf.capacity())}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ChannelBuffer duplicate(); /** * Converts this buffer's readable bytes into a NIO buffer. The returned * buffer might or might not share the content with this buffer, while * they have separate indexes and marks. This method is identical to * {@code buf.toByteBuffer(buf.readerIndex(), buf.readableBytes())}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ByteBuffer toByteBuffer(); /** * Converts this buffer's sub-region into a NIO buffer. The returned * buffer might or might not share the content with this buffer, while * they have separate indexes and marks. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ByteBuffer toByteBuffer(int index, int length); /** * Converts this buffer's readable bytes into an array of NIO buffers. * The returned buffers might or might not share the content with this * buffer, while they have separate indexes and marks. This method is * identical to {@code buf.toByteBuffers(buf.readerIndex(), buf.readableBytes())}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ByteBuffer[] toByteBuffers(); /** * Converts this buffer's sub-region into an array of NIO buffers. * The returned buffers might or might not share the content with this * buffer, while they have separate indexes and marks. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. */ ByteBuffer[] toByteBuffers(int index, int length); /** * Returns {@code true} if and only if this buffer has a backing byte array. * If this method returns true, you can safely call {@link #array()} and * {@link #arrayOffset()}. */ boolean hasArray(); /** * Returns the backing byte array of this buffer. * * @throws UnsupportedOperationException * if there no accessible backing byte array */ byte[] array(); /** * Returns the offset of the first byte within the backing byte array of * this buffer. * * @throws UnsupportedOperationException * if there no accessible backing byte array */ int arrayOffset(); /** * Decodes this buffer's readable bytes into a string with the specified * character set name. This method is identical to * {@code buf.toString(buf.readerIndex(), buf.readableBytes(), charsetName)}. * This method does not modify {@code readerIndex} or {@code writerIndex} of * this buffer. * * @throws UnsupportedCharsetException * if the specified character set name is not supported by the * current VM */ String toString(Charset charset); /** * Decodes this buffer's sub-region into a string with the specified * character set. This method does not modify {@code readerIndex} or * {@code writerIndex} of this buffer. */ String toString(int index, int length, Charset charset); /** * @deprecated Use {@link #toString(Charset)} instead. */ @Deprecated String toString(String charsetName); /** * @deprecated Use {@link #bytesBefore(ChannelBufferIndexFinder)} and {@link #toString(int, int, Charset)} instead. */ @Deprecated String toString( String charsetName, ChannelBufferIndexFinder terminatorFinder); /** * @deprecated Use {@link #bytesBefore(int, int, ChannelBufferIndexFinder)} and * {@link #toString(int, int, Charset)} instead. */ @Deprecated String toString(int index, int length, String charsetName); /** * @deprecated Use {@link #bytesBefore(int, int, ChannelBufferIndexFinder)} and * {@link #toString(int, int, Charset)} instead. */ @Deprecated String toString( int index, int length, String charsetName, ChannelBufferIndexFinder terminatorFinder); /** * Returns a hash code which was calculated from the content of this * buffer. If there's a byte array which is * {@linkplain #equals(Object) equal to} this array, both arrays should * return the same value. */ int hashCode(); /** * Determines if the content of the specified buffer is identical to the * content of this array. 'Identical' here means: *

    *
  • the size of the contents of the two buffers are same and
  • *
  • every single byte of the content of the two buffers are same.
  • *
* Please note that it does not compare {@link #readerIndex()} nor * {@link #writerIndex()}. This method also returns {@code false} for * {@code null} and an object which is not an instance of * {@link ChannelBuffer} type. */ boolean equals(Object obj); /** * Compares the content of the specified buffer to the content of this * buffer. Comparison is performed in the same manner with the string * comparison functions of various languages such as {@code strcmp}, * {@code memcmp} and {@link String#compareTo(String)}. */ int compareTo(ChannelBuffer buffer); /** * Returns the string representation of this buffer. This method does not * necessarily return the whole content of the buffer but returns * the values of the key properties such as {@link #readerIndex()}, * {@link #writerIndex()} and {@link #capacity()}. */ String toString(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ChannelBufferFactory.java000066400000000000000000000104061225554127700307460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * A factory that creates or pools {@link ChannelBuffer}s. */ public interface ChannelBufferFactory { /** * Returns a {@link ChannelBuffer} with the specified {@code capacity}. * This method is identical to {@code getBuffer(getDefaultOrder(), capacity)}. * * @param capacity the capacity of the returned {@link ChannelBuffer} * @return a {@link ChannelBuffer} with the specified {@code capacity}, * whose {@code readerIndex} and {@code writerIndex} are {@code 0} */ ChannelBuffer getBuffer(int capacity); /** * Returns a {@link ChannelBuffer} with the specified {@code endianness} * and {@code capacity}. * * @param endianness the endianness of the returned {@link ChannelBuffer} * @param capacity the capacity of the returned {@link ChannelBuffer} * @return a {@link ChannelBuffer} with the specified {@code endianness} and * {@code capacity}, whose {@code readerIndex} and {@code writerIndex} * are {@code 0} */ ChannelBuffer getBuffer(ByteOrder endianness, int capacity); /** * Returns a {@link ChannelBuffer} whose content is equal to the sub-region * of the specified {@code array}. Depending on the factory implementation, * the returned buffer could wrap the {@code array} or create a new copy of * the {@code array}. * This method is identical to {@code getBuffer(getDefaultOrder(), array, offset, length)}. * * @param array the byte array * @param offset the offset of the byte array * @param length the length of the byte array * * @return a {@link ChannelBuffer} with the specified content, * whose {@code readerIndex} and {@code writerIndex} * are {@code 0} and {@code (length - offset)} respectively */ ChannelBuffer getBuffer(byte[] array, int offset, int length); /** * Returns a {@link ChannelBuffer} whose content is equal to the sub-region * of the specified {@code array}. Depending on the factory implementation, * the returned buffer could wrap the {@code array} or create a new copy of * the {@code array}. * * @param endianness the endianness of the returned {@link ChannelBuffer} * @param array the byte array * @param offset the offset of the byte array * @param length the length of the byte array * * @return a {@link ChannelBuffer} with the specified content, * whose {@code readerIndex} and {@code writerIndex} * are {@code 0} and {@code (length - offset)} respectively */ ChannelBuffer getBuffer(ByteOrder endianness, byte[] array, int offset, int length); /** * Returns a {@link ChannelBuffer} whose content is equal to the sub-region * of the specified {@code nioBuffer}. Depending on the factory * implementation, the returned buffer could wrap the {@code nioBuffer} or * create a new copy of the {@code nioBuffer}. * * @param nioBuffer the NIO {@link ByteBuffer} * * @return a {@link ChannelBuffer} with the specified content, * whose {@code readerIndex} and {@code writerIndex} * are {@code 0} and {@code nioBuffer.remaining()} respectively */ ChannelBuffer getBuffer(ByteBuffer nioBuffer); /** * Returns the default endianness of the {@link ChannelBuffer} which is * returned by {@link #getBuffer(int)}. * * @return the default endianness of the {@link ChannelBuffer} which is * returned by {@link #getBuffer(int)} */ ByteOrder getDefaultOrder(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ChannelBufferIndexFinder.java000066400000000000000000000113721225554127700315410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; /** * Locates an index of data in a {@link ChannelBuffer}. *

* This interface enables the sequential search for the data which meets more * complex and dynamic condition than just a simple value matching. Please * refer to {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)} and * {@link ChannelBuffer#bytesBefore(int, int, ChannelBufferIndexFinder)} * for more explanation. * * @apiviz.uses org.jboss.netty.buffer.ChannelBuffer */ public interface ChannelBufferIndexFinder { /** * Returns {@code true} if and only if the data is found at the specified * {@code guessedIndex} of the specified {@code buffer}. *

* The implementation should not perform an operation which raises an * exception such as {@link IndexOutOfBoundsException} nor perform * an operation which modifies the content of the buffer. */ boolean find(ChannelBuffer buffer, int guessedIndex); /** * Index finder which locates a {@code NUL (0x00)} byte. */ ChannelBufferIndexFinder NUL = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return buffer.getByte(guessedIndex) == 0; } }; /** * Index finder which locates a non-{@code NUL (0x00)} byte. */ ChannelBufferIndexFinder NOT_NUL = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return buffer.getByte(guessedIndex) != 0; } }; /** * Index finder which locates a {@code CR ('\r')} byte. */ ChannelBufferIndexFinder CR = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return buffer.getByte(guessedIndex) == '\r'; } }; /** * Index finder which locates a non-{@code CR ('\r')} byte. */ ChannelBufferIndexFinder NOT_CR = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return buffer.getByte(guessedIndex) != '\r'; } }; /** * Index finder which locates a {@code LF ('\n')} byte. */ ChannelBufferIndexFinder LF = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return buffer.getByte(guessedIndex) == '\n'; } }; /** * Index finder which locates a non-{@code LF ('\n')} byte. */ ChannelBufferIndexFinder NOT_LF = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return buffer.getByte(guessedIndex) != '\n'; } }; /** * Index finder which locates a {@code CR ('\r')} or {@code LF ('\n')}. */ ChannelBufferIndexFinder CRLF = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { byte b = buffer.getByte(guessedIndex); return b == '\r' || b == '\n'; } }; /** * Index finder which locates a byte which is neither a {@code CR ('\r')} * nor a {@code LF ('\n')}. */ ChannelBufferIndexFinder NOT_CRLF = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { byte b = buffer.getByte(guessedIndex); return b != '\r' && b != '\n'; } }; /** * Index finder which locates a linear whitespace * ({@code ' '} and {@code '\t'}). */ ChannelBufferIndexFinder LINEAR_WHITESPACE = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { byte b = buffer.getByte(guessedIndex); return b == ' ' || b == '\t'; } }; /** * Index finder which locates a byte which is not a linear whitespace * (neither {@code ' '} nor {@code '\t'}). */ ChannelBufferIndexFinder NOT_LINEAR_WHITESPACE = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { byte b = buffer.getByte(guessedIndex); return b != ' ' && b != '\t'; } }; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ChannelBufferInputStream.java000066400000000000000000000150251225554127700316140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.DataInput; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; /** * An {@link InputStream} which reads data from a {@link ChannelBuffer}. *

* A read operation against this stream will occur at the {@code readerIndex} * of its underlying buffer and the {@code readerIndex} will increase during * the read operation. *

* This stream implements {@link DataInput} for your convenience. * The endianness of the stream is not always big endian but depends on * the endianness of the underlying buffer. * * @see ChannelBufferOutputStream * @apiviz.uses org.jboss.netty.buffer.ChannelBuffer */ public class ChannelBufferInputStream extends InputStream implements DataInput { private final ChannelBuffer buffer; private final int startIndex; private final int endIndex; /** * Creates a new stream which reads data from the specified {@code buffer} * starting at the current {@code readerIndex} and ending at the current * {@code writerIndex}. */ public ChannelBufferInputStream(ChannelBuffer buffer) { this(buffer, buffer.readableBytes()); } /** * Creates a new stream which reads data from the specified {@code buffer} * starting at the current {@code readerIndex} and ending at * {@code readerIndex + length}. * * @throws IndexOutOfBoundsException * if {@code readerIndex + length} is greater than * {@code writerIndex} */ public ChannelBufferInputStream(ChannelBuffer buffer, int length) { if (buffer == null) { throw new NullPointerException("buffer"); } if (length < 0) { throw new IllegalArgumentException("length: " + length); } if (length > buffer.readableBytes()) { throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + length + ", maximum is " + buffer.readableBytes()); } this.buffer = buffer; startIndex = buffer.readerIndex(); endIndex = startIndex + length; buffer.markReaderIndex(); } /** * Returns the number of read bytes by this stream so far. */ public int readBytes() { return buffer.readerIndex() - startIndex; } @Override public int available() throws IOException { return endIndex - buffer.readerIndex(); } @Override public void mark(int readlimit) { buffer.markReaderIndex(); } @Override public boolean markSupported() { return true; } @Override public int read() throws IOException { if (!buffer.readable()) { return -1; } return buffer.readByte() & 0xff; } @Override public int read(byte[] b, int off, int len) throws IOException { int available = available(); if (available == 0) { return -1; } len = Math.min(available, len); buffer.readBytes(b, off, len); return len; } @Override public void reset() throws IOException { buffer.resetReaderIndex(); } @Override public long skip(long n) throws IOException { if (n > Integer.MAX_VALUE) { return skipBytes(Integer.MAX_VALUE); } else { return skipBytes((int) n); } } public boolean readBoolean() throws IOException { checkAvailable(1); return read() != 0; } public byte readByte() throws IOException { if (!buffer.readable()) { throw new EOFException(); } return buffer.readByte(); } public char readChar() throws IOException { return (char) readShort(); } public double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } public float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } public void readFully(byte[] b) throws IOException { readFully(b, 0, b.length); } public void readFully(byte[] b, int off, int len) throws IOException { checkAvailable(len); buffer.readBytes(b, off, len); } public int readInt() throws IOException { checkAvailable(4); return buffer.readInt(); } private final StringBuilder lineBuf = new StringBuilder(); public String readLine() throws IOException { lineBuf.setLength(0); for (;;) { int b = read(); if (b < 0 || b == '\n') { break; } lineBuf.append((char) b); } if (lineBuf.length() > 0) { while (lineBuf.charAt(lineBuf.length() - 1) == '\r') { lineBuf.setLength(lineBuf.length() - 1); } } return lineBuf.toString(); } public long readLong() throws IOException { checkAvailable(8); return buffer.readLong(); } public short readShort() throws IOException { checkAvailable(2); return buffer.readShort(); } public String readUTF() throws IOException { return DataInputStream.readUTF(this); } public int readUnsignedByte() throws IOException { return readByte() & 0xff; } public int readUnsignedShort() throws IOException { return readShort() & 0xffff; } public int skipBytes(int n) throws IOException { int nBytes = Math.min(available(), n); buffer.skipBytes(nBytes); return nBytes; } private void checkAvailable(int fieldSize) throws IOException { if (fieldSize < 0) { throw new IndexOutOfBoundsException("fieldSize cannot be a negative number"); } if (fieldSize > available()) { throw new EOFException("fieldSize is too long! Length is " + fieldSize + ", but maximum is " + available()); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ChannelBufferOutputStream.java000066400000000000000000000074071225554127700320220ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; /** * An {@link OutputStream} which writes data to a {@link ChannelBuffer}. *

* A write operation against this stream will occur at the {@code writerIndex} * of its underlying buffer and the {@code writerIndex} will increase during * the write operation. *

* This stream implements {@link DataOutput} for your convenience. * The endianness of the stream is not always big endian but depends on * the endianness of the underlying buffer. * * @see ChannelBufferInputStream * @apiviz.uses org.jboss.netty.buffer.ChannelBuffer */ public class ChannelBufferOutputStream extends OutputStream implements DataOutput { private final ChannelBuffer buffer; private final int startIndex; private final DataOutputStream utf8out = new DataOutputStream(this); /** * Creates a new stream which writes data to the specified {@code buffer}. */ public ChannelBufferOutputStream(ChannelBuffer buffer) { if (buffer == null) { throw new NullPointerException("buffer"); } this.buffer = buffer; startIndex = buffer.writerIndex(); } /** * Returns the number of written bytes by this stream so far. */ public int writtenBytes() { return buffer.writerIndex() - startIndex; } @Override public void write(byte[] b, int off, int len) throws IOException { if (len == 0) { return; } buffer.writeBytes(b, off, len); } @Override public void write(byte[] b) throws IOException { buffer.writeBytes(b); } @Override public void write(int b) throws IOException { buffer.writeByte((byte) b); } public void writeBoolean(boolean v) throws IOException { write(v? (byte) 1 : (byte) 0); } public void writeByte(int v) throws IOException { write(v); } public void writeBytes(String s) throws IOException { int len = s.length(); for (int i = 0; i < len; i ++) { write((byte) s.charAt(i)); } } public void writeChar(int v) throws IOException { writeShort((short) v); } public void writeChars(String s) throws IOException { int len = s.length(); for (int i = 0 ; i < len ; i ++) { writeChar(s.charAt(i)); } } public void writeDouble(double v) throws IOException { writeLong(Double.doubleToLongBits(v)); } public void writeFloat(float v) throws IOException { writeInt(Float.floatToIntBits(v)); } public void writeInt(int v) throws IOException { buffer.writeInt(v); } public void writeLong(long v) throws IOException { buffer.writeLong(v); } public void writeShort(int v) throws IOException { buffer.writeShort((short) v); } public void writeUTF(String s) throws IOException { utf8out.writeUTF(s); } /** * Returns the buffer where this stream is writing data. */ public ChannelBuffer buffer() { return buffer; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ChannelBuffers.java000066400000000000000000001254701225554127700276110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import org.jboss.netty.util.CharsetUtil; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.util.ArrayList; import java.util.List; /** * Creates a new {@link ChannelBuffer} by allocating new space or by wrapping * or copying existing byte arrays, byte buffers and a string. * *

Use static import

* This classes is intended to be used with Java 5 static import statement: * *
 * import static org.jboss.netty.buffer.{@link ChannelBuffers}.*;
 *
 * {@link ChannelBuffer} heapBuffer    = buffer(128);
 * {@link ChannelBuffer} directBuffer  = directBuffer(256);
 * {@link ChannelBuffer} dynamicBuffer = dynamicBuffer(512);
 * {@link ChannelBuffer} wrappedBuffer = wrappedBuffer(new byte[128], new byte[256]);
 * {@link ChannelBuffer} copiedBuffe r = copiedBuffer({@link ByteBuffer}.allocate(128));
 * 
* *

Allocating a new buffer

* * Three buffer types are provided out of the box. * *
    *
  • {@link #buffer(int)} allocates a new fixed-capacity heap buffer.
  • *
  • {@link #directBuffer(int)} allocates a new fixed-capacity direct buffer.
  • *
  • {@link #dynamicBuffer(int)} allocates a new dynamic-capacity heap * buffer, whose capacity increases automatically as needed by a write * operation.
  • *
* *

Creating a wrapped buffer

* * Wrapped buffer is a buffer which is a view of one or more existing * byte arrays and byte buffers. Any changes in the content of the original * array or buffer will be visible in the wrapped buffer. Various wrapper * methods are provided and their name is all {@code wrappedBuffer()}. * You might want to take a look at the methods that accept varargs closely if * you want to create a buffer which is composed of more than one array to * reduce the number of memory copy. * *

Creating a copied buffer

* * Copied buffer is a deep copy of one or more existing byte arrays, byte * buffers or a string. Unlike a wrapped buffer, there's no shared data * between the original data and the copied buffer. Various copy methods are * provided and their name is all {@code copiedBuffer()}. It is also convenient * to use this operation to merge multiple buffers into one buffer. * *

Miscellaneous utility methods

* * This class also provides various utility methods to help implementation * of a new buffer type, generation of hex dump and swapping an integer's * byte order. * * @apiviz.landmark * @apiviz.has org.jboss.netty.buffer.ChannelBuffer oneway - - creates */ public final class ChannelBuffers { /** * Big endian byte order. */ public static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN; /** * Little endian byte order. */ public static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN; /** * A buffer whose capacity is {@code 0}. */ public static final ChannelBuffer EMPTY_BUFFER = new EmptyChannelBuffer(); private static final char[] HEXDUMP_TABLE = new char[256 * 4]; static { final char[] DIGITS = "0123456789abcdef".toCharArray(); for (int i = 0; i < 256; i ++) { HEXDUMP_TABLE[i << 1] = DIGITS[i >>> 4 & 0x0F]; HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F]; } } /** * Creates a new big-endian Java heap buffer with the specified * {@code capacity}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0}. */ public static ChannelBuffer buffer(int capacity) { return buffer(BIG_ENDIAN, capacity); } /** * Creates a new Java heap buffer with the specified {@code endianness} * and {@code capacity}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0}. */ public static ChannelBuffer buffer(ByteOrder endianness, int capacity) { if (endianness == BIG_ENDIAN) { if (capacity == 0) { return EMPTY_BUFFER; } return new BigEndianHeapChannelBuffer(capacity); } else if (endianness == LITTLE_ENDIAN) { if (capacity == 0) { return EMPTY_BUFFER; } return new LittleEndianHeapChannelBuffer(capacity); } else { throw new NullPointerException("endianness"); } } /** * Creates a new big-endian direct buffer with the specified * {@code capacity}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0}. */ public static ChannelBuffer directBuffer(int capacity) { return directBuffer(BIG_ENDIAN, capacity); } /** * Creates a new direct buffer with the specified {@code endianness} and * {@code capacity}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0}. */ public static ChannelBuffer directBuffer(ByteOrder endianness, int capacity) { if (endianness == null) { throw new NullPointerException("endianness"); } if (capacity == 0) { return EMPTY_BUFFER; } ChannelBuffer buffer = new ByteBufferBackedChannelBuffer( ByteBuffer.allocateDirect(capacity).order(endianness)); buffer.clear(); return buffer; } /** * Creates a new big-endian dynamic buffer whose estimated data length is * {@code 256} bytes. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0}. */ public static ChannelBuffer dynamicBuffer() { return dynamicBuffer(BIG_ENDIAN, 256); } public static ChannelBuffer dynamicBuffer(ChannelBufferFactory factory) { if (factory == null) { throw new NullPointerException("factory"); } return new DynamicChannelBuffer(factory.getDefaultOrder(), 256, factory); } /** * Creates a new big-endian dynamic buffer with the specified estimated * data length. More accurate estimation yields less unexpected * reallocation overhead. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0}. */ public static ChannelBuffer dynamicBuffer(int estimatedLength) { return dynamicBuffer(BIG_ENDIAN, estimatedLength); } /** * Creates a new dynamic buffer with the specified endianness and * the specified estimated data length. More accurate estimation yields * less unexpected reallocation overhead. The new buffer's * {@code readerIndex} and {@code writerIndex} are {@code 0}. */ public static ChannelBuffer dynamicBuffer(ByteOrder endianness, int estimatedLength) { return new DynamicChannelBuffer(endianness, estimatedLength); } /** * Creates a new big-endian dynamic buffer with the specified estimated * data length using the specified factory. More accurate estimation yields * less unexpected reallocation overhead. The new buffer's {@code readerIndex} * and {@code writerIndex} are {@code 0}. */ public static ChannelBuffer dynamicBuffer(int estimatedLength, ChannelBufferFactory factory) { if (factory == null) { throw new NullPointerException("factory"); } return new DynamicChannelBuffer(factory.getDefaultOrder(), estimatedLength, factory); } /** * Creates a new dynamic buffer with the specified endianness and * the specified estimated data length using the specified factory. * More accurate estimation yields less unexpected reallocation overhead. * The new buffer's {@code readerIndex} and {@code writerIndex} are {@code 0}. */ public static ChannelBuffer dynamicBuffer( ByteOrder endianness, int estimatedLength, ChannelBufferFactory factory) { return new DynamicChannelBuffer(endianness, estimatedLength, factory); } /** * Creates a new big-endian buffer which wraps the specified {@code array}. * A modification on the specified array's content will be visible to the * returned buffer. */ public static ChannelBuffer wrappedBuffer(byte[] array) { return wrappedBuffer(BIG_ENDIAN, array); } /** * Creates a new buffer which wraps the specified {@code array} with the * specified {@code endianness}. A modification on the specified array's * content will be visible to the returned buffer. */ public static ChannelBuffer wrappedBuffer(ByteOrder endianness, byte[] array) { if (endianness == BIG_ENDIAN) { if (array.length == 0) { return EMPTY_BUFFER; } return new BigEndianHeapChannelBuffer(array); } else if (endianness == LITTLE_ENDIAN) { if (array.length == 0) { return EMPTY_BUFFER; } return new LittleEndianHeapChannelBuffer(array); } else { throw new NullPointerException("endianness"); } } /** * Creates a new big-endian buffer which wraps the sub-region of the * specified {@code array}. A modification on the specified array's * content will be visible to the returned buffer. */ public static ChannelBuffer wrappedBuffer(byte[] array, int offset, int length) { return wrappedBuffer(BIG_ENDIAN, array, offset, length); } /** * Creates a new buffer which wraps the sub-region of the specified * {@code array} with the specified {@code endianness}. A modification on * the specified array's content will be visible to the returned buffer. */ public static ChannelBuffer wrappedBuffer(ByteOrder endianness, byte[] array, int offset, int length) { if (endianness == null) { throw new NullPointerException("endianness"); } if (offset == 0) { if (length == array.length) { return wrappedBuffer(endianness, array); } else { if (length == 0) { return EMPTY_BUFFER; } else { return new TruncatedChannelBuffer(wrappedBuffer(endianness, array), length); } } } else { if (length == 0) { return EMPTY_BUFFER; } else { return new SlicedChannelBuffer(wrappedBuffer(endianness, array), offset, length); } } } /** * Creates a new buffer which wraps the specified NIO buffer's current * slice. A modification on the specified buffer's content will be * visible to the returned buffer. */ public static ChannelBuffer wrappedBuffer(ByteBuffer buffer) { if (!buffer.hasRemaining()) { return EMPTY_BUFFER; } if (buffer.hasArray()) { return wrappedBuffer( buffer.order(), buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); } else { return new ByteBufferBackedChannelBuffer(buffer); } } /** * Creates a new buffer which wraps the specified buffer's readable bytes. * A modification on the specified buffer's content will be visible to the * returned buffer. */ public static ChannelBuffer wrappedBuffer(ChannelBuffer buffer) { if (buffer.readable()) { return buffer.slice(); } else { return EMPTY_BUFFER; } } /** * Creates a new big-endian composite buffer which wraps the specified * arrays without copying them. A modification on the specified arrays' * content will be visible to the returned buffer. */ public static ChannelBuffer wrappedBuffer(byte[]... arrays) { return wrappedBuffer(BIG_ENDIAN, arrays); } /** * Creates a new composite buffer which wraps the specified arrays without * copying them. A modification on the specified arrays' content will be * visible to the returned buffer. * * @param endianness the endianness of the new buffer */ public static ChannelBuffer wrappedBuffer(ByteOrder endianness, byte[]... arrays) { switch (arrays.length) { case 0: break; case 1: if (arrays[0].length != 0) { return wrappedBuffer(endianness, arrays[0]); } break; default: // Get the list of the component, while guessing the byte order. final List components = new ArrayList(arrays.length); for (byte[] a: arrays) { if (a == null) { break; } if (a.length > 0) { components.add(wrappedBuffer(endianness, a)); } } return compositeBuffer(endianness, components, false); } return EMPTY_BUFFER; } private static ChannelBuffer compositeBuffer( ByteOrder endianness, List components, boolean gathering) { switch (components.size()) { case 0: return EMPTY_BUFFER; case 1: return components.get(0); default: return new CompositeChannelBuffer(endianness, components, gathering); } } /** * Creates a new composite buffer which wraps the readable bytes of the * specified buffers without copying them. A modification on the content * of the specified buffers will be visible to the returned buffer. * * @throws IllegalArgumentException * if the specified buffers' endianness are different from each * other */ public static ChannelBuffer wrappedBuffer(ChannelBuffer... buffers) { return wrappedBuffer(false, buffers); } /** * Creates a new composite buffer which wraps the readable bytes of the * specified buffers without copying them. A modification on the content * of the specified buffers will be visible to the returned buffer. * If gathering is {@code true} then gathering writes will be used when ever * possible. * * @throws IllegalArgumentException * if the specified buffers' endianness are different from each * other */ public static ChannelBuffer wrappedBuffer(boolean gathering, ChannelBuffer... buffers) { switch (buffers.length) { case 0: break; case 1: if (buffers[0].readable()) { return wrappedBuffer(buffers[0]); } break; default: ByteOrder order = null; final List components = new ArrayList(buffers.length); for (ChannelBuffer c: buffers) { if (c == null) { break; } if (c.readable()) { if (order != null) { if (!order.equals(c.order())) { throw new IllegalArgumentException( "inconsistent byte order"); } } else { order = c.order(); } if (c instanceof CompositeChannelBuffer) { // Expand nested composition. components.addAll( ((CompositeChannelBuffer) c).decompose( c.readerIndex(), c.readableBytes())); } else { // An ordinary buffer (non-composite) components.add(c.slice()); } } } return compositeBuffer(order, components, gathering); } return EMPTY_BUFFER; } /** * Creates a new composite buffer which wraps the slices of the specified * NIO buffers without copying them. A modification on the content of the * specified buffers will be visible to the returned buffer. * * @throws IllegalArgumentException * if the specified buffers' endianness are different from each * other */ public static ChannelBuffer wrappedBuffer(ByteBuffer... buffers) { return wrappedBuffer(false, buffers); } /** * Creates a new composite buffer which wraps the slices of the specified * NIO buffers without copying them. A modification on the content of the * specified buffers will be visible to the returned buffer. * If gathering is {@code true} then gathering writes will be used when ever * possible. * * @throws IllegalArgumentException * if the specified buffers' endianness are different from each * other */ public static ChannelBuffer wrappedBuffer(boolean gathering, ByteBuffer... buffers) { switch (buffers.length) { case 0: break; case 1: if (buffers[0].hasRemaining()) { return wrappedBuffer(buffers[0]); } break; default: ByteOrder order = null; final List components = new ArrayList(buffers.length); for (ByteBuffer b: buffers) { if (b == null) { break; } if (b.hasRemaining()) { if (order != null) { if (!order.equals(b.order())) { throw new IllegalArgumentException( "inconsistent byte order"); } } else { order = b.order(); } components.add(wrappedBuffer(b)); } } return compositeBuffer(order, components, gathering); } return EMPTY_BUFFER; } /** * Creates a new big-endian buffer whose content is a copy of the * specified {@code array}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0} and {@code array.length} respectively. */ public static ChannelBuffer copiedBuffer(byte[] array) { return copiedBuffer(BIG_ENDIAN, array); } /** * Creates a new buffer with the specified {@code endianness} whose * content is a copy of the specified {@code array}. The new buffer's * {@code readerIndex} and {@code writerIndex} are {@code 0} and * {@code array.length} respectively. */ public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[] array) { if (endianness == BIG_ENDIAN) { if (array.length == 0) { return EMPTY_BUFFER; } return new BigEndianHeapChannelBuffer(array.clone()); } else if (endianness == LITTLE_ENDIAN) { if (array.length == 0) { return EMPTY_BUFFER; } return new LittleEndianHeapChannelBuffer(array.clone()); } else { throw new NullPointerException("endianness"); } } /** * Creates a new big-endian buffer whose content is a copy of the * specified {@code array}'s sub-region. The new buffer's * {@code readerIndex} and {@code writerIndex} are {@code 0} and * the specified {@code length} respectively. */ public static ChannelBuffer copiedBuffer(byte[] array, int offset, int length) { return copiedBuffer(BIG_ENDIAN, array, offset, length); } /** * Creates a new buffer with the specified {@code endianness} whose * content is a copy of the specified {@code array}'s sub-region. The new * buffer's {@code readerIndex} and {@code writerIndex} are {@code 0} and * the specified {@code length} respectively. */ public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[] array, int offset, int length) { if (endianness == null) { throw new NullPointerException("endianness"); } if (length == 0) { return EMPTY_BUFFER; } byte[] copy = new byte[length]; System.arraycopy(array, offset, copy, 0, length); return wrappedBuffer(endianness, copy); } /** * Creates a new buffer whose content is a copy of the specified * {@code buffer}'s current slice. The new buffer's {@code readerIndex} * and {@code writerIndex} are {@code 0} and {@code buffer.remaining} * respectively. */ public static ChannelBuffer copiedBuffer(ByteBuffer buffer) { int length = buffer.remaining(); if (length == 0) { return EMPTY_BUFFER; } byte[] copy = new byte[length]; int position = buffer.position(); try { buffer.get(copy); } finally { buffer.position(position); } return wrappedBuffer(buffer.order(), copy); } /** * Creates a new buffer whose content is a copy of the specified * {@code buffer}'s readable bytes. The new buffer's {@code readerIndex} * and {@code writerIndex} are {@code 0} and {@code buffer.readableBytes} * respectively. */ public static ChannelBuffer copiedBuffer(ChannelBuffer buffer) { if (buffer.readable()) { return buffer.copy(); } else { return EMPTY_BUFFER; } } /** * Creates a new big-endian buffer whose content is a merged copy of * the specified {@code arrays}. The new buffer's {@code readerIndex} * and {@code writerIndex} are {@code 0} and the sum of all arrays' * {@code length} respectively. */ public static ChannelBuffer copiedBuffer(byte[]... arrays) { return copiedBuffer(BIG_ENDIAN, arrays); } /** * Creates a new buffer with the specified {@code endianness} whose * content is a merged copy of the specified {@code arrays}. The new * buffer's {@code readerIndex} and {@code writerIndex} are {@code 0} * and the sum of all arrays' {@code length} respectively. */ public static ChannelBuffer copiedBuffer(ByteOrder endianness, byte[]... arrays) { switch (arrays.length) { case 0: return EMPTY_BUFFER; case 1: if (arrays[0].length == 0) { return EMPTY_BUFFER; } else { return copiedBuffer(endianness, arrays[0]); } } // Merge the specified arrays into one array. int length = 0; for (byte[] a: arrays) { if (Integer.MAX_VALUE - length < a.length) { throw new IllegalArgumentException( "The total length of the specified arrays is too big."); } length += a.length; } if (length == 0) { return EMPTY_BUFFER; } byte[] mergedArray = new byte[length]; for (int i = 0, j = 0; i < arrays.length; i ++) { byte[] a = arrays[i]; System.arraycopy(a, 0, mergedArray, j, a.length); j += a.length; } return wrappedBuffer(endianness, mergedArray); } /** * Creates a new buffer whose content is a merged copy of the specified * {@code buffers}' readable bytes. The new buffer's {@code readerIndex} * and {@code writerIndex} are {@code 0} and the sum of all buffers' * {@code readableBytes} respectively. * * @throws IllegalArgumentException * if the specified buffers' endianness are different from each * other */ public static ChannelBuffer copiedBuffer(ChannelBuffer... buffers) { switch (buffers.length) { case 0: return EMPTY_BUFFER; case 1: return copiedBuffer(buffers[0]); } ChannelBuffer[] copiedBuffers = new ChannelBuffer[buffers.length]; for (int i = 0; i < buffers.length; i ++) { copiedBuffers[i] = copiedBuffer(buffers[i]); } return wrappedBuffer(false, copiedBuffers); } /** * Creates a new buffer whose content is a merged copy of the specified * {@code buffers}' slices. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0} and the sum of all buffers' * {@code remaining} respectively. * * @throws IllegalArgumentException * if the specified buffers' endianness are different from each * other */ public static ChannelBuffer copiedBuffer(ByteBuffer... buffers) { switch (buffers.length) { case 0: return EMPTY_BUFFER; case 1: return copiedBuffer(buffers[0]); } ChannelBuffer[] copiedBuffers = new ChannelBuffer[buffers.length]; for (int i = 0; i < buffers.length; i ++) { copiedBuffers[i] = copiedBuffer(buffers[i]); } return wrappedBuffer(false, copiedBuffers); } /** * Creates a new big-endian buffer whose content is the specified * {@code string} encoded in the specified {@code charset}. * The new buffer's {@code readerIndex} and {@code writerIndex} are * {@code 0} and the length of the encoded string respectively. */ public static ChannelBuffer copiedBuffer(CharSequence string, Charset charset) { return copiedBuffer(BIG_ENDIAN, string, charset); } /** * Creates a new big-endian buffer whose content is a subregion of * the specified {@code string} encoded in the specified {@code charset}. * The new buffer's {@code readerIndex} and {@code writerIndex} are * {@code 0} and the length of the encoded string respectively. */ public static ChannelBuffer copiedBuffer( CharSequence string, int offset, int length, Charset charset) { return copiedBuffer(BIG_ENDIAN, string, offset, length, charset); } /** * Creates a new buffer with the specified {@code endianness} whose * content is the specified {@code string} encoded in the specified * {@code charset}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0} and the length of the encoded string * respectively. */ public static ChannelBuffer copiedBuffer(ByteOrder endianness, CharSequence string, Charset charset) { if (string == null) { throw new NullPointerException("string"); } if (string instanceof CharBuffer) { return copiedBuffer(endianness, (CharBuffer) string, charset); } return copiedBuffer(endianness, CharBuffer.wrap(string), charset); } /** * Creates a new buffer with the specified {@code endianness} whose * content is a subregion of the specified {@code string} encoded in the * specified {@code charset}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0} and the length of the encoded string * respectively. */ public static ChannelBuffer copiedBuffer( ByteOrder endianness, CharSequence string, int offset, int length, Charset charset) { if (string == null) { throw new NullPointerException("string"); } if (length == 0) { return EMPTY_BUFFER; } if (string instanceof CharBuffer) { CharBuffer buf = (CharBuffer) string; if (buf.hasArray()) { return copiedBuffer( endianness, buf.array(), buf.arrayOffset() + buf.position() + offset, length, charset); } buf = buf.slice(); buf.limit(length); buf.position(offset); return copiedBuffer(endianness, buf, charset); } return copiedBuffer( endianness, CharBuffer.wrap(string, offset, offset + length), charset); } /** * Creates a new big-endian buffer whose content is the specified * {@code array} encoded in the specified {@code charset}. * The new buffer's {@code readerIndex} and {@code writerIndex} are * {@code 0} and the length of the encoded string respectively. */ public static ChannelBuffer copiedBuffer(char[] array, Charset charset) { return copiedBuffer(BIG_ENDIAN, array, 0, array.length, charset); } /** * Creates a new big-endian buffer whose content is a subregion of * the specified {@code array} encoded in the specified {@code charset}. * The new buffer's {@code readerIndex} and {@code writerIndex} are * {@code 0} and the length of the encoded string respectively. */ public static ChannelBuffer copiedBuffer( char[] array, int offset, int length, Charset charset) { return copiedBuffer(BIG_ENDIAN, array, offset, length, charset); } /** * Creates a new buffer with the specified {@code endianness} whose * content is the specified {@code array} encoded in the specified * {@code charset}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0} and the length of the encoded string * respectively. */ public static ChannelBuffer copiedBuffer(ByteOrder endianness, char[] array, Charset charset) { return copiedBuffer(endianness, array, 0, array.length, charset); } /** * Creates a new buffer with the specified {@code endianness} whose * content is a subregion of the specified {@code array} encoded in the * specified {@code charset}. The new buffer's {@code readerIndex} and * {@code writerIndex} are {@code 0} and the length of the encoded string * respectively. */ public static ChannelBuffer copiedBuffer( ByteOrder endianness, char[] array, int offset, int length, Charset charset) { if (array == null) { throw new NullPointerException("array"); } if (length == 0) { return EMPTY_BUFFER; } return copiedBuffer( endianness, CharBuffer.wrap(array, offset, length), charset); } private static ChannelBuffer copiedBuffer(ByteOrder endianness, CharBuffer buffer, Charset charset) { CharBuffer src = buffer; ByteBuffer dst = encodeString(src, charset); ChannelBuffer result = wrappedBuffer(endianness, dst.array()); result.writerIndex(dst.remaining()); return result; } /** * @deprecated Use {@link #copiedBuffer(CharSequence, Charset)} instead. */ @Deprecated public static ChannelBuffer copiedBuffer(String string, String charsetName) { return copiedBuffer(string, Charset.forName(charsetName)); } /** * @deprecated Use {@link #copiedBuffer(ByteOrder, CharSequence, Charset)} instead. */ @Deprecated public static ChannelBuffer copiedBuffer(ByteOrder endianness, String string, String charsetName) { return copiedBuffer(endianness, string, Charset.forName(charsetName)); } /** * Creates a read-only buffer which disallows any modification operations * on the specified {@code buffer}. The new buffer has the same * {@code readerIndex} and {@code writerIndex} with the specified * {@code buffer}. */ public static ChannelBuffer unmodifiableBuffer(ChannelBuffer buffer) { if (buffer instanceof ReadOnlyChannelBuffer) { buffer = ((ReadOnlyChannelBuffer) buffer).unwrap(); } return new ReadOnlyChannelBuffer(buffer); } /** * Create a {@link ChannelBuffer} from the given hex dump */ public static ChannelBuffer hexDump(String hexString) { int len = hexString.length(); byte[] hexData = new byte[len / 2]; for (int i = 0; i < len; i += 2) { hexData[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); } return wrappedBuffer(hexData); } /** * Returns a hex dump * of the specified buffer's readable bytes. */ public static String hexDump(ChannelBuffer buffer) { return hexDump(buffer, buffer.readerIndex(), buffer.readableBytes()); } /** * Returns a hex dump * of the specified buffer's sub-region. */ public static String hexDump(ChannelBuffer buffer, int fromIndex, int length) { if (length < 0) { throw new IllegalArgumentException("length: " + length); } if (length == 0) { return ""; } int endIndex = fromIndex + length; char[] buf = new char[length << 1]; int srcIdx = fromIndex; int dstIdx = 0; for (; srcIdx < endIndex; srcIdx ++, dstIdx += 2) { System.arraycopy( HEXDUMP_TABLE, buffer.getUnsignedByte(srcIdx) << 1, buf, dstIdx, 2); } return new String(buf); } /** * Calculates the hash code of the specified buffer. This method is * useful when implementing a new buffer type. */ public static int hashCode(ChannelBuffer buffer) { final int aLen = buffer.readableBytes(); final int intCount = aLen >>> 2; final int byteCount = aLen & 3; int hashCode = 1; int arrayIndex = buffer.readerIndex(); if (buffer.order() == BIG_ENDIAN) { for (int i = intCount; i > 0; i --) { hashCode = 31 * hashCode + buffer.getInt(arrayIndex); arrayIndex += 4; } } else { for (int i = intCount; i > 0; i --) { hashCode = 31 * hashCode + swapInt(buffer.getInt(arrayIndex)); arrayIndex += 4; } } for (int i = byteCount; i > 0; i --) { hashCode = 31 * hashCode + buffer.getByte(arrayIndex ++); } if (hashCode == 0) { hashCode = 1; } return hashCode; } /** * Returns {@code true} if and only if the two specified buffers are * identical to each other as described in {@code ChannelBuffer#equals(Object)}. * This method is useful when implementing a new buffer type. */ public static boolean equals(ChannelBuffer bufferA, ChannelBuffer bufferB) { final int aLen = bufferA.readableBytes(); if (aLen != bufferB.readableBytes()) { return false; } final int longCount = aLen >>> 3; final int byteCount = aLen & 7; int aIndex = bufferA.readerIndex(); int bIndex = bufferB.readerIndex(); if (bufferA.order() == bufferB.order()) { for (int i = longCount; i > 0; i --) { if (bufferA.getLong(aIndex) != bufferB.getLong(bIndex)) { return false; } aIndex += 8; bIndex += 8; } } else { for (int i = longCount; i > 0; i --) { if (bufferA.getLong(aIndex) != swapLong(bufferB.getLong(bIndex))) { return false; } aIndex += 8; bIndex += 8; } } for (int i = byteCount; i > 0; i --) { if (bufferA.getByte(aIndex) != bufferB.getByte(bIndex)) { return false; } aIndex ++; bIndex ++; } return true; } /** * Compares the two specified buffers as described in {@link ChannelBuffer#compareTo(ChannelBuffer)}. * This method is useful when implementing a new buffer type. */ public static int compare(ChannelBuffer bufferA, ChannelBuffer bufferB) { final int aLen = bufferA.readableBytes(); final int bLen = bufferB.readableBytes(); final int minLength = Math.min(aLen, bLen); final int uintCount = minLength >>> 2; final int byteCount = minLength & 3; int aIndex = bufferA.readerIndex(); int bIndex = bufferB.readerIndex(); if (bufferA.order() == bufferB.order()) { for (int i = uintCount; i > 0; i --) { long va = bufferA.getUnsignedInt(aIndex); long vb = bufferB.getUnsignedInt(bIndex); if (va > vb) { return 1; } if (va < vb) { return -1; } aIndex += 4; bIndex += 4; } } else { for (int i = uintCount; i > 0; i --) { long va = bufferA.getUnsignedInt(aIndex); long vb = swapInt(bufferB.getInt(bIndex)) & 0xFFFFFFFFL; if (va > vb) { return 1; } if (va < vb) { return -1; } aIndex += 4; bIndex += 4; } } for (int i = byteCount; i > 0; i --) { short va = bufferA.getUnsignedByte(aIndex); short vb = bufferB.getUnsignedByte(bIndex); if (va > vb) { return 1; } if (va < vb) { return -1; } aIndex ++; bIndex ++; } return aLen - bLen; } /** * The default implementation of {@link ChannelBuffer#indexOf(int, int, byte)}. * This method is useful when implementing a new buffer type. */ public static int indexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) { if (fromIndex <= toIndex) { return firstIndexOf(buffer, fromIndex, toIndex, value); } else { return lastIndexOf(buffer, fromIndex, toIndex, value); } } /** * The default implementation of {@link ChannelBuffer#indexOf(int, int, ChannelBufferIndexFinder)}. * This method is useful when implementing a new buffer type. */ public static int indexOf( ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) { if (fromIndex <= toIndex) { return firstIndexOf(buffer, fromIndex, toIndex, indexFinder); } else { return lastIndexOf(buffer, fromIndex, toIndex, indexFinder); } } /** * Toggles the endianness of the specified 16-bit short integer. */ public static short swapShort(short value) { return (short) (value << 8 | value >>> 8 & 0xff); } /** * Toggles the endianness of the specified 24-bit medium integer. */ public static int swapMedium(int value) { return value << 16 & 0xff0000 | value & 0xff00 | value >>> 16 & 0xff; } /** * Toggles the endianness of the specified 32-bit integer. */ public static int swapInt(int value) { return swapShort((short) value) << 16 | swapShort((short) (value >>> 16)) & 0xffff; } /** * Toggles the endianness of the specified 64-bit long integer. */ public static long swapLong(long value) { return (long) swapInt((int) value) << 32 | swapInt((int) (value >>> 32)) & 0xffffffffL; } private static int firstIndexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) { fromIndex = Math.max(fromIndex, 0); if (fromIndex >= toIndex || buffer.capacity() == 0) { return -1; } for (int i = fromIndex; i < toIndex; i ++) { if (buffer.getByte(i) == value) { return i; } } return -1; } private static int lastIndexOf(ChannelBuffer buffer, int fromIndex, int toIndex, byte value) { fromIndex = Math.min(fromIndex, buffer.capacity()); if (fromIndex < 0 || buffer.capacity() == 0) { return -1; } for (int i = fromIndex - 1; i >= toIndex; i --) { if (buffer.getByte(i) == value) { return i; } } return -1; } private static int firstIndexOf( ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) { fromIndex = Math.max(fromIndex, 0); if (fromIndex >= toIndex || buffer.capacity() == 0) { return -1; } for (int i = fromIndex; i < toIndex; i ++) { if (indexFinder.find(buffer, i)) { return i; } } return -1; } private static int lastIndexOf( ChannelBuffer buffer, int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) { fromIndex = Math.min(fromIndex, buffer.capacity()); if (fromIndex < 0 || buffer.capacity() == 0) { return -1; } for (int i = fromIndex - 1; i >= toIndex; i --) { if (indexFinder.find(buffer, i)) { return i; } } return -1; } static ByteBuffer encodeString(CharBuffer src, Charset charset) { final CharsetEncoder encoder = CharsetUtil.getEncoder(charset); final ByteBuffer dst = ByteBuffer.allocate( (int) ((double) src.remaining() * encoder.maxBytesPerChar())); try { CoderResult cr = encoder.encode(src, dst, true); if (!cr.isUnderflow()) { cr.throwException(); } cr = encoder.flush(dst); if (!cr.isUnderflow()) { cr.throwException(); } } catch (CharacterCodingException x) { throw new IllegalStateException(x); } dst.flip(); return dst; } static String decodeString(ByteBuffer src, Charset charset) { final CharsetDecoder decoder = CharsetUtil.getDecoder(charset); final CharBuffer dst = CharBuffer.allocate( (int) ((double) src.remaining() * decoder.maxCharsPerByte())); try { CoderResult cr = decoder.decode(src, dst, true); if (!cr.isUnderflow()) { cr.throwException(); } cr = decoder.flush(dst); if (!cr.isUnderflow()) { cr.throwException(); } } catch (CharacterCodingException x) { throw new IllegalStateException(x); } return dst.flip().toString(); } private ChannelBuffers() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/CompositeChannelBuffer.java000066400000000000000000000663221225554127700313110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import org.jboss.netty.util.internal.DetectionUtil; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * A virtual buffer which shows multiple buffers as a single merged buffer. It * is recommended to use {@link ChannelBuffers#wrappedBuffer(ChannelBuffer...)} * instead of calling the constructor explicitly. */ public class CompositeChannelBuffer extends AbstractChannelBuffer { private final ByteOrder order; private ChannelBuffer[] components; private int[] indices; private int lastAccessedComponentId; private final boolean gathering; public CompositeChannelBuffer(ByteOrder endianness, List buffers, boolean gathering) { order = endianness; this.gathering = gathering; setComponents(buffers); } /** * Return {@code true} if gathering writes / reads should be used * for this {@link CompositeChannelBuffer} */ public boolean useGathering() { return gathering && DetectionUtil.javaVersion() >= 7; } /** * Same with {@link #slice(int, int)} except that this method returns a list. */ public List decompose(int index, int length) { if (length == 0) { return Collections.emptyList(); } if (index + length > capacity()) { throw new IndexOutOfBoundsException("Too many bytes to decompose - Need " + (index + length) + ", capacity is " + capacity()); } int componentId = componentId(index); List slice = new ArrayList(components.length); // The first component ChannelBuffer first = components[componentId].duplicate(); first.readerIndex(index - indices[componentId]); ChannelBuffer buf = first; int bytesToSlice = length; do { int readableBytes = buf.readableBytes(); if (bytesToSlice <= readableBytes) { // Last component buf.writerIndex(buf.readerIndex() + bytesToSlice); slice.add(buf); break; } else { // Not the last component slice.add(buf); bytesToSlice -= readableBytes; componentId ++; // Fetch the next component. buf = components[componentId].duplicate(); } } while (bytesToSlice > 0); // Slice all components because only readable bytes are interesting. for (int i = 0; i < slice.size(); i ++) { slice.set(i, slice.get(i).slice()); } return slice; } /** * Setup this ChannelBuffer from the list */ private void setComponents(List newComponents) { assert !newComponents.isEmpty(); // Clear the cache. lastAccessedComponentId = 0; // Build the component array. components = new ChannelBuffer[newComponents.size()]; for (int i = 0; i < components.length; i ++) { ChannelBuffer c = newComponents.get(i); if (c.order() != order()) { throw new IllegalArgumentException( "All buffers must have the same endianness."); } assert c.readerIndex() == 0; assert c.writerIndex() == c.capacity(); components[i] = c; } // Build the component lookup table. indices = new int[components.length + 1]; indices[0] = 0; for (int i = 1; i <= components.length; i ++) { indices[i] = indices[i - 1] + components[i - 1].capacity(); } // Reset the indexes. setIndex(0, capacity()); } private CompositeChannelBuffer(CompositeChannelBuffer buffer) { order = buffer.order; gathering = buffer.gathering; components = buffer.components.clone(); indices = buffer.indices.clone(); setIndex(buffer.readerIndex(), buffer.writerIndex()); } public ChannelBufferFactory factory() { return HeapChannelBufferFactory.getInstance(order()); } public ByteOrder order() { return order; } public boolean isDirect() { return false; } public boolean hasArray() { return false; } public byte[] array() { throw new UnsupportedOperationException(); } public int arrayOffset() { throw new UnsupportedOperationException(); } public int capacity() { return indices[components.length]; } public int numComponents() { return components.length; } public byte getByte(int index) { int componentId = componentId(index); return components[componentId].getByte(index - indices[componentId]); } public short getShort(int index) { int componentId = componentId(index); if (index + 2 <= indices[componentId + 1]) { return components[componentId].getShort(index - indices[componentId]); } else if (order() == ByteOrder.BIG_ENDIAN) { return (short) ((getByte(index) & 0xff) << 8 | getByte(index + 1) & 0xff); } else { return (short) (getByte(index) & 0xff | (getByte(index + 1) & 0xff) << 8); } } public int getUnsignedMedium(int index) { int componentId = componentId(index); if (index + 3 <= indices[componentId + 1]) { return components[componentId].getUnsignedMedium(index - indices[componentId]); } else if (order() == ByteOrder.BIG_ENDIAN) { return (getShort(index) & 0xffff) << 8 | getByte(index + 2) & 0xff; } else { return getShort(index) & 0xFFFF | (getByte(index + 2) & 0xFF) << 16; } } public int getInt(int index) { int componentId = componentId(index); if (index + 4 <= indices[componentId + 1]) { return components[componentId].getInt(index - indices[componentId]); } else if (order() == ByteOrder.BIG_ENDIAN) { return (getShort(index) & 0xffff) << 16 | getShort(index + 2) & 0xffff; } else { return getShort(index) & 0xFFFF | (getShort(index + 2) & 0xFFFF) << 16; } } public long getLong(int index) { int componentId = componentId(index); if (index + 8 <= indices[componentId + 1]) { return components[componentId].getLong(index - indices[componentId]); } else if (order() == ByteOrder.BIG_ENDIAN) { return (getInt(index) & 0xffffffffL) << 32 | getInt(index + 4) & 0xffffffffL; } else { return getInt(index) & 0xFFFFFFFFL | (getInt(index + 4) & 0xFFFFFFFFL) << 32; } } public void getBytes(int index, byte[] dst, int dstIndex, int length) { if (index > capacity() - length || dstIndex > dst.length - length) { throw new IndexOutOfBoundsException("Too many bytes to read - Needs " + (index + length) + ", maximum is " + capacity() + " or " + dst.length); } if (index < 0) { throw new IndexOutOfBoundsException("Index must be >= 0"); } if (length == 0) { return; } int componentId = componentId(index); int i = componentId; while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); s.getBytes(index - adjustment, dst, dstIndex, localLength); index += localLength; dstIndex += localLength; length -= localLength; i ++; } } public void getBytes(int index, ByteBuffer dst) { int componentId = componentId(index); int limit = dst.limit(); int length = dst.remaining(); if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + (index + length) + ", maximum is " + capacity()); } if (index < 0) { throw new IndexOutOfBoundsException("Index must be >= 0"); } int i = componentId; try { while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); dst.limit(dst.position() + localLength); s.getBytes(index - adjustment, dst); index += localLength; length -= localLength; i ++; } } finally { dst.limit(limit); } } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { if (index > capacity() - length || dstIndex > dst.capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + (index + length) + " or " + (dstIndex + length) + ", maximum is " + capacity() + " or " + dst.capacity()); } if (index < 0) { throw new IndexOutOfBoundsException("Index must be >= 0"); } if (length == 0) { return; } int i = componentId(index); while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); s.getBytes(index - adjustment, dst, dstIndex, localLength); index += localLength; dstIndex += localLength; length -= localLength; i ++; } } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { if (useGathering()) { return (int) out.write(toByteBuffers(index, length)); } // XXX Gathering write is not supported because of a known issue. // See http://bugs.sun.com/view_bug.do?bug_id=6210541 // This issue appeared in 2004 and is still unresolved!? return out.write(toByteBuffer(index, length)); } public void getBytes(int index, OutputStream out, int length) throws IOException { if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be read - needs " + (index + length) + ", maximum of " + capacity()); } if (index < 0) { throw new IndexOutOfBoundsException("Index must be >= 0"); } if (length == 0) { return; } int i = componentId(index); while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); s.getBytes(index - adjustment, out, localLength); index += localLength; length -= localLength; i ++; } } public void setByte(int index, int value) { int componentId = componentId(index); components[componentId].setByte(index - indices[componentId], value); } public void setShort(int index, int value) { int componentId = componentId(index); if (index + 2 <= indices[componentId + 1]) { components[componentId].setShort(index - indices[componentId], value); } else if (order() == ByteOrder.BIG_ENDIAN) { setByte(index, (byte) (value >>> 8)); setByte(index + 1, (byte) value); } else { setByte(index , (byte) value); setByte(index + 1, (byte) (value >>> 8)); } } public void setMedium(int index, int value) { int componentId = componentId(index); if (index + 3 <= indices[componentId + 1]) { components[componentId].setMedium(index - indices[componentId], value); } else if (order() == ByteOrder.BIG_ENDIAN) { setShort(index, (short) (value >> 8)); setByte(index + 2, (byte) value); } else { setShort(index , (short) value); setByte(index + 2, (byte) (value >>> 16)); } } public void setInt(int index, int value) { int componentId = componentId(index); if (index + 4 <= indices[componentId + 1]) { components[componentId].setInt(index - indices[componentId], value); } else if (order() == ByteOrder.BIG_ENDIAN) { setShort(index, (short) (value >>> 16)); setShort(index + 2, (short) value); } else { setShort(index , (short) value); setShort(index + 2, (short) (value >>> 16)); } } public void setLong(int index, long value) { int componentId = componentId(index); if (index + 8 <= indices[componentId + 1]) { components[componentId].setLong(index - indices[componentId], value); } else if (order() == ByteOrder.BIG_ENDIAN) { setInt(index, (int) (value >>> 32)); setInt(index + 4, (int) value); } else { setInt(index , (int) value); setInt(index + 4, (int) (value >>> 32)); } } public void setBytes(int index, byte[] src, int srcIndex, int length) { int componentId = componentId(index); if (index > capacity() - length || srcIndex > src.length - length) { throw new IndexOutOfBoundsException("Too many bytes to read - needs " + (index + length) + " or " + (srcIndex + length) + ", maximum is " + capacity() + " or " + src.length); } int i = componentId; while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); s.setBytes(index - adjustment, src, srcIndex, localLength); index += localLength; srcIndex += localLength; length -= localLength; i ++; } } public void setBytes(int index, ByteBuffer src) { int componentId = componentId(index); int limit = src.limit(); int length = src.remaining(); if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be written - Needs " + (index + length) + ", maximum is " + capacity()); } int i = componentId; try { while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); src.limit(src.position() + localLength); s.setBytes(index - adjustment, src); index += localLength; length -= localLength; i ++; } } finally { src.limit(limit); } } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { int componentId = componentId(index); if (index > capacity() - length || srcIndex > src.capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be written - Needs " + (index + length) + " or " + (srcIndex + length) + ", maximum is " + capacity() + " or " + src.capacity()); } int i = componentId; while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); s.setBytes(index - adjustment, src, srcIndex, localLength); index += localLength; srcIndex += localLength; length -= localLength; i ++; } } public int setBytes(int index, InputStream in, int length) throws IOException { int componentId = componentId(index); if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to write - Needs " + (index + length) + ", maximum is " + capacity()); } int i = componentId; int readBytes = 0; do { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); int localReadBytes = s.setBytes(index - adjustment, in, localLength); if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } if (localReadBytes == localLength) { index += localLength; length -= localLength; readBytes += localLength; i ++; } else { index += localReadBytes; length -= localReadBytes; readBytes += localReadBytes; } } while (length > 0); return readBytes; } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { int componentId = componentId(index); if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to write - Needs " + (index + length) + ", maximum is " + capacity()); } int i = componentId; int readBytes = 0; do { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); int localReadBytes = s.setBytes(index - adjustment, in, localLength); if (localReadBytes == 0) { break; } if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } if (localReadBytes == localLength) { index += localLength; length -= localLength; readBytes += localLength; i ++; } else { index += localReadBytes; length -= localReadBytes; readBytes += localReadBytes; } } while (length > 0); return readBytes; } public ChannelBuffer duplicate() { ChannelBuffer duplicate = new CompositeChannelBuffer(this); duplicate.setIndex(readerIndex(), writerIndex()); return duplicate; } public ChannelBuffer copy(int index, int length) { int componentId = componentId(index); if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to copy - Needs " + (index + length) + ", maximum is " + capacity()); } ChannelBuffer dst = factory().getBuffer(order(), length); copyTo(index, length, componentId, dst); return dst; } private void copyTo(int index, int length, int componentId, ChannelBuffer dst) { int dstIndex = 0; int i = componentId; while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); s.getBytes(index - adjustment, dst, dstIndex, localLength); index += localLength; dstIndex += localLength; length -= localLength; i ++; } dst.writerIndex(dst.capacity()); } /** * Returns the {@link ChannelBuffer} portion of this {@link CompositeChannelBuffer} that * contains the specified {@code index}. This is an expert method! * *

* Please note that since a {@link CompositeChannelBuffer} is made up of * multiple {@link ChannelBuffer}s, this does not return the full buffer. * Instead, it only returns a portion of the composite buffer where the * index is located *

* * * @param index The {@code index} to search for and include in the returned {@link ChannelBuffer} * @return The {@link ChannelBuffer} that contains the specified {@code index} * @throws IndexOutOfBoundsException when the specified {@code index} is * less than zero, or larger than {@code capacity()} */ public ChannelBuffer getBuffer(int index) { if (index < 0 || index >= capacity()) { throw new IndexOutOfBoundsException("Invalid index: " + index + " - Bytes needed: " + index + ", maximum is " + capacity()); } //Return the component byte buffer return components[componentId(index)]; } public ChannelBuffer slice(int index, int length) { if (index == 0) { if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } } else if (index < 0 || index > capacity() - length) { throw new IndexOutOfBoundsException("Invalid index: " + index + " - Bytes needed: " + (index + length) + ", maximum is " + capacity()); } else if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } List components = decompose(index, length); switch (components.size()) { case 0: return ChannelBuffers.EMPTY_BUFFER; case 1: return components.get(0); default: return new CompositeChannelBuffer(order(), components, gathering); } } public ByteBuffer toByteBuffer(int index, int length) { if (components.length == 1) { return components[0].toByteBuffer(index, length); } ByteBuffer[] buffers = toByteBuffers(index, length); ByteBuffer merged = ByteBuffer.allocate(length).order(order()); for (ByteBuffer b: buffers) { merged.put(b); } merged.flip(); return merged; } @Override public ByteBuffer[] toByteBuffers(int index, int length) { if (index + length > capacity()) { throw new IndexOutOfBoundsException("Too many bytes to convert - Needs" + (index + length) + ", maximum is " + capacity()); } if (index < 0) { throw new IndexOutOfBoundsException("Index must be >= 0"); } if (length == 0) { return new ByteBuffer[0]; } List buffers = new ArrayList(components.length); int i = componentId(index); while (length > 0) { ChannelBuffer s = components[i]; int adjustment = indices[i]; int localLength = Math.min(length, s.capacity() - (index - adjustment)); buffers.add(s.toByteBuffer(index - adjustment, localLength)); index += localLength; length -= localLength; i ++; } return buffers.toArray(new ByteBuffer[buffers.size()]); } private int componentId(int index) { int lastComponentId = lastAccessedComponentId; if (index >= indices[lastComponentId]) { if (index < indices[lastComponentId + 1]) { return lastComponentId; } // Search right for (int i = lastComponentId + 1; i < components.length; i ++) { if (index < indices[i + 1]) { lastAccessedComponentId = i; return i; } } } else { // Search left for (int i = lastComponentId - 1; i >= 0; i --) { if (index >= indices[i]) { lastAccessedComponentId = i; return i; } } } throw new IndexOutOfBoundsException("Invalid index: " + index + ", maximum: " + indices.length); } @Override public void discardReadBytes() { // Only the bytes between readerIndex and writerIndex will be kept. // New readerIndex and writerIndex will become 0 and // (previous writerIndex - previous readerIndex) respectively. final int localReaderIndex = readerIndex(); if (localReaderIndex == 0) { return; } int localWriterIndex = writerIndex(); final int bytesToMove = capacity() - localReaderIndex; List list = decompose(localReaderIndex, bytesToMove); // If the list is empty we need to assign a new one because // we get a List that is immutable. // // See https://github.com/netty/netty/issues/325 if (list.isEmpty()) { list = new ArrayList(1); } // Add a new buffer so that the capacity of this composite buffer does // not decrease due to the discarded components. // XXX Might create too many components if discarded by small amount. final ChannelBuffer padding = ChannelBuffers.buffer(order(), localReaderIndex); padding.writerIndex(localReaderIndex); list.add(padding); // Reset the index markers to get the index marker values. int localMarkedReaderIndex = localReaderIndex; try { resetReaderIndex(); localMarkedReaderIndex = readerIndex(); } catch (IndexOutOfBoundsException e) { // ignore } int localMarkedWriterIndex = localWriterIndex; try { resetWriterIndex(); localMarkedWriterIndex = writerIndex(); } catch (IndexOutOfBoundsException e) { // ignore } setComponents(list); // reset marked Indexes localMarkedReaderIndex = Math.max(localMarkedReaderIndex - localReaderIndex, 0); localMarkedWriterIndex = Math.max(localMarkedWriterIndex - localReaderIndex, 0); setIndex(localMarkedReaderIndex, localMarkedWriterIndex); markReaderIndex(); markWriterIndex(); // reset real indexes localWriterIndex = Math.max(localWriterIndex - localReaderIndex, 0); setIndex(0, localWriterIndex); } @Override public String toString() { String result = super.toString(); result = result.substring(0, result.length() - 1); return result + ", components=" + components.length + ')'; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/DirectChannelBufferFactory.java000066400000000000000000000167701225554127700321130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.lang.ref.ReferenceQueue; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * A {@link ChannelBufferFactory} which pre-allocates a large chunk of direct * buffer and returns its slice on demand. Direct buffers are reclaimed via * {@link ReferenceQueue} in most JDK implementations, and therefore they are * deallocated less efficiently than an ordinary heap buffer. Consequently, * a user will get {@link OutOfMemoryError} when one tries to allocate small * direct buffers more often than the GC throughput of direct buffers, which * is much lower than the GC throughput of heap buffers. This factory avoids * this problem by allocating a large chunk of pre-allocated direct buffer and * reducing the number of the garbage collected internal direct buffer objects. */ public class DirectChannelBufferFactory extends AbstractChannelBufferFactory { private static final DirectChannelBufferFactory INSTANCE_BE = new DirectChannelBufferFactory(ByteOrder.BIG_ENDIAN); private static final DirectChannelBufferFactory INSTANCE_LE = new DirectChannelBufferFactory(ByteOrder.LITTLE_ENDIAN); public static ChannelBufferFactory getInstance() { return INSTANCE_BE; } public static ChannelBufferFactory getInstance(ByteOrder defaultEndianness) { if (defaultEndianness == ByteOrder.BIG_ENDIAN) { return INSTANCE_BE; } else if (defaultEndianness == ByteOrder.LITTLE_ENDIAN) { return INSTANCE_LE; } else if (defaultEndianness == null) { throw new NullPointerException("defaultEndianness"); } else { throw new IllegalStateException("Should not reach here"); } } private final Object bigEndianLock = new Object(); private final Object littleEndianLock = new Object(); private final int preallocatedBufCapacity; private ChannelBuffer preallocatedBEBuf; private int preallocatedBEBufPos; private ChannelBuffer preallocatedLEBuf; private int preallocatedLEBufPos; /** * Creates a new factory whose default {@link ByteOrder} is * {@link ByteOrder#BIG_ENDIAN}. */ public DirectChannelBufferFactory() { this(ByteOrder.BIG_ENDIAN); } /** * Creates a new factory whose default {@link ByteOrder} is * {@link ByteOrder#BIG_ENDIAN}. */ public DirectChannelBufferFactory(int preallocatedBufferCapacity) { this(ByteOrder.BIG_ENDIAN, preallocatedBufferCapacity); } /** * Creates a new factory with the specified default {@link ByteOrder}. * * @param defaultOrder the default {@link ByteOrder} of this factory */ public DirectChannelBufferFactory(ByteOrder defaultOrder) { this(defaultOrder, 1048576); } /** * Creates a new factory with the specified default {@link ByteOrder}. * * @param defaultOrder the default {@link ByteOrder} of this factory */ public DirectChannelBufferFactory(ByteOrder defaultOrder, int preallocatedBufferCapacity) { super(defaultOrder); if (preallocatedBufferCapacity <= 0) { throw new IllegalArgumentException( "preallocatedBufCapacity must be greater than 0: " + preallocatedBufferCapacity); } preallocatedBufCapacity = preallocatedBufferCapacity; } public ChannelBuffer getBuffer(ByteOrder order, int capacity) { if (order == null) { throw new NullPointerException("order"); } if (capacity < 0) { throw new IllegalArgumentException("capacity: " + capacity); } if (capacity == 0) { return ChannelBuffers.EMPTY_BUFFER; } if (capacity >= preallocatedBufCapacity) { return ChannelBuffers.directBuffer(order, capacity); } ChannelBuffer slice; if (order == ByteOrder.BIG_ENDIAN) { slice = allocateBigEndianBuffer(capacity); } else { slice = allocateLittleEndianBuffer(capacity); } slice.clear(); return slice; } public ChannelBuffer getBuffer(ByteOrder order, byte[] array, int offset, int length) { if (array == null) { throw new NullPointerException("array"); } if (offset < 0) { throw new IndexOutOfBoundsException("offset: " + offset); } if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } if (offset + length > array.length) { throw new IndexOutOfBoundsException("length: " + length); } ChannelBuffer buf = getBuffer(order, length); buf.writeBytes(array, offset, length); return buf; } public ChannelBuffer getBuffer(ByteBuffer nioBuffer) { if (!nioBuffer.isReadOnly() && nioBuffer.isDirect()) { return ChannelBuffers.wrappedBuffer(nioBuffer); } ChannelBuffer buf = getBuffer(nioBuffer.order(), nioBuffer.remaining()); int pos = nioBuffer.position(); buf.writeBytes(nioBuffer); nioBuffer.position(pos); return buf; } private ChannelBuffer allocateBigEndianBuffer(int capacity) { ChannelBuffer slice; synchronized (bigEndianLock) { if (preallocatedBEBuf == null) { preallocatedBEBuf = ChannelBuffers.directBuffer(ByteOrder.BIG_ENDIAN, preallocatedBufCapacity); slice = preallocatedBEBuf.slice(0, capacity); preallocatedBEBufPos = capacity; } else if (preallocatedBEBuf.capacity() - preallocatedBEBufPos >= capacity) { slice = preallocatedBEBuf.slice(preallocatedBEBufPos, capacity); preallocatedBEBufPos += capacity; } else { preallocatedBEBuf = ChannelBuffers.directBuffer(ByteOrder.BIG_ENDIAN, preallocatedBufCapacity); slice = preallocatedBEBuf.slice(0, capacity); preallocatedBEBufPos = capacity; } } return slice; } private ChannelBuffer allocateLittleEndianBuffer(int capacity) { ChannelBuffer slice; synchronized (littleEndianLock) { if (preallocatedLEBuf == null) { preallocatedLEBuf = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, preallocatedBufCapacity); slice = preallocatedLEBuf.slice(0, capacity); preallocatedLEBufPos = capacity; } else if (preallocatedLEBuf.capacity() - preallocatedLEBufPos >= capacity) { slice = preallocatedLEBuf.slice(preallocatedLEBufPos, capacity); preallocatedLEBufPos += capacity; } else { preallocatedLEBuf = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, preallocatedBufCapacity); slice = preallocatedLEBuf.slice(0, capacity); preallocatedLEBufPos = capacity; } } return slice; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/DuplicatedChannelBuffer.java000066400000000000000000000115601225554127700314170ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A derived buffer which simply forwards all data access requests to its * parent. It is recommended to use {@link ChannelBuffer#duplicate()} instead * of calling the constructor explicitly. */ public class DuplicatedChannelBuffer extends AbstractChannelBuffer implements WrappedChannelBuffer { private final ChannelBuffer buffer; public DuplicatedChannelBuffer(ChannelBuffer buffer) { if (buffer == null) { throw new NullPointerException("buffer"); } this.buffer = buffer; setIndex(buffer.readerIndex(), buffer.writerIndex()); } private DuplicatedChannelBuffer(DuplicatedChannelBuffer buffer) { this.buffer = buffer.buffer; setIndex(buffer.readerIndex(), buffer.writerIndex()); } public ChannelBuffer unwrap() { return buffer; } public ChannelBufferFactory factory() { return buffer.factory(); } public ByteOrder order() { return buffer.order(); } public boolean isDirect() { return buffer.isDirect(); } public int capacity() { return buffer.capacity(); } public boolean hasArray() { return buffer.hasArray(); } public byte[] array() { return buffer.array(); } public int arrayOffset() { return buffer.arrayOffset(); } public byte getByte(int index) { return buffer.getByte(index); } public short getShort(int index) { return buffer.getShort(index); } public int getUnsignedMedium(int index) { return buffer.getUnsignedMedium(index); } public int getInt(int index) { return buffer.getInt(index); } public long getLong(int index) { return buffer.getLong(index); } public ChannelBuffer duplicate() { return new DuplicatedChannelBuffer(this); } public ChannelBuffer copy(int index, int length) { return buffer.copy(index, length); } public ChannelBuffer slice(int index, int length) { return buffer.slice(index, length); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, byte[] dst, int dstIndex, int length) { buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { buffer.getBytes(index, dst); } public void setByte(int index, int value) { buffer.setByte(index, value); } public void setShort(int index, int value) { buffer.setShort(index, value); } public void setMedium(int index, int value) { buffer.setMedium(index, value); } public void setInt(int index, int value) { buffer.setInt(index, value); } public void setLong(int index, long value) { buffer.setLong(index, value); } public void setBytes(int index, byte[] src, int srcIndex, int length) { buffer.setBytes(index, src, srcIndex, length); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { buffer.setBytes(index, src, srcIndex, length); } public void setBytes(int index, ByteBuffer src) { buffer.setBytes(index, src); } public void getBytes(int index, OutputStream out, int length) throws IOException { buffer.getBytes(index, out, length); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { return buffer.getBytes(index, out, length); } public int setBytes(int index, InputStream in, int length) throws IOException { return buffer.setBytes(index, in, length); } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { return buffer.setBytes(index, in, length); } public ByteBuffer toByteBuffer(int index, int length) { return buffer.toByteBuffer(index, length); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/DynamicChannelBuffer.java000066400000000000000000000204451225554127700307270ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A dynamic capacity buffer which increases its capacity as needed. It is * recommended to use {@link ChannelBuffers#dynamicBuffer(int)} instead of * calling the constructor explicitly. */ public class DynamicChannelBuffer extends AbstractChannelBuffer { private final ChannelBufferFactory factory; private final ByteOrder endianness; private ChannelBuffer buffer; public DynamicChannelBuffer(int estimatedLength) { this(ByteOrder.BIG_ENDIAN, estimatedLength); } public DynamicChannelBuffer(ByteOrder endianness, int estimatedLength) { this(endianness, estimatedLength, HeapChannelBufferFactory.getInstance(endianness)); } public DynamicChannelBuffer(ByteOrder endianness, int estimatedLength, ChannelBufferFactory factory) { if (estimatedLength < 0) { throw new IllegalArgumentException("estimatedLength: " + estimatedLength); } if (endianness == null) { throw new NullPointerException("endianness"); } if (factory == null) { throw new NullPointerException("factory"); } this.factory = factory; this.endianness = endianness; buffer = factory.getBuffer(order(), estimatedLength); } @Override public void ensureWritableBytes(int minWritableBytes) { if (minWritableBytes <= writableBytes()) { return; } int newCapacity; if (capacity() == 0) { newCapacity = 1; } else { newCapacity = capacity(); } int minNewCapacity = writerIndex() + minWritableBytes; while (newCapacity < minNewCapacity) { newCapacity <<= 1; // Check if we exceeded the maximum size of 2gb if this is the case then // newCapacity == 0 // // https://github.com/netty/netty/issues/258 if (newCapacity == 0) { throw new IllegalStateException("Maximum size of 2gb exceeded"); } } ChannelBuffer newBuffer = factory().getBuffer(order(), newCapacity); newBuffer.writeBytes(buffer, 0, writerIndex()); buffer = newBuffer; } public ChannelBufferFactory factory() { return factory; } public ByteOrder order() { return endianness; } public boolean isDirect() { return buffer.isDirect(); } public int capacity() { return buffer.capacity(); } public boolean hasArray() { return buffer.hasArray(); } public byte[] array() { return buffer.array(); } public int arrayOffset() { return buffer.arrayOffset(); } public byte getByte(int index) { return buffer.getByte(index); } public short getShort(int index) { return buffer.getShort(index); } public int getUnsignedMedium(int index) { return buffer.getUnsignedMedium(index); } public int getInt(int index) { return buffer.getInt(index); } public long getLong(int index) { return buffer.getLong(index); } public void getBytes(int index, byte[] dst, int dstIndex, int length) { buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { buffer.getBytes(index, dst); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { return buffer.getBytes(index, out, length); } public void getBytes(int index, OutputStream out, int length) throws IOException { buffer.getBytes(index, out, length); } public void setByte(int index, int value) { buffer.setByte(index, value); } public void setShort(int index, int value) { buffer.setShort(index, value); } public void setMedium(int index, int value) { buffer.setMedium(index, value); } public void setInt(int index, int value) { buffer.setInt(index, value); } public void setLong(int index, long value) { buffer.setLong(index, value); } public void setBytes(int index, byte[] src, int srcIndex, int length) { buffer.setBytes(index, src, srcIndex, length); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { buffer.setBytes(index, src, srcIndex, length); } public void setBytes(int index, ByteBuffer src) { buffer.setBytes(index, src); } public int setBytes(int index, InputStream in, int length) throws IOException { return buffer.setBytes(index, in, length); } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { return buffer.setBytes(index, in, length); } @Override public void writeByte(int value) { ensureWritableBytes(1); super.writeByte(value); } @Override public void writeShort(int value) { ensureWritableBytes(2); super.writeShort(value); } @Override public void writeMedium(int value) { ensureWritableBytes(3); super.writeMedium(value); } @Override public void writeInt(int value) { ensureWritableBytes(4); super.writeInt(value); } @Override public void writeLong(long value) { ensureWritableBytes(8); super.writeLong(value); } @Override public void writeBytes(byte[] src, int srcIndex, int length) { ensureWritableBytes(length); super.writeBytes(src, srcIndex, length); } @Override public void writeBytes(ChannelBuffer src, int srcIndex, int length) { ensureWritableBytes(length); super.writeBytes(src, srcIndex, length); } @Override public void writeBytes(ByteBuffer src) { ensureWritableBytes(src.remaining()); super.writeBytes(src); } @Override public int writeBytes(InputStream in, int length) throws IOException { ensureWritableBytes(length); return super.writeBytes(in, length); } @Override public int writeBytes(ScatteringByteChannel in, int length) throws IOException { ensureWritableBytes(length); return super.writeBytes(in, length); } @Override public void writeZero(int length) { ensureWritableBytes(length); super.writeZero(length); } public ChannelBuffer duplicate() { return new DuplicatedChannelBuffer(this); } public ChannelBuffer copy(int index, int length) { DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(order(), Math.max(length, 64), factory()); copiedBuffer.buffer = buffer.copy(index, length); copiedBuffer.setIndex(0, length); return copiedBuffer; } public ChannelBuffer slice(int index, int length) { if (index == 0) { if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } return new TruncatedChannelBuffer(this, length); } else { if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } return new SlicedChannelBuffer(this, index, length); } } public ByteBuffer toByteBuffer(int index, int length) { return buffer.toByteBuffer(index, length); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/EmptyChannelBuffer.java000066400000000000000000000132641225554127700304420ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * An immutable empty buffer implementation. Typically used as a singleton via * {@link ChannelBuffers#EMPTY_BUFFER} and returned by {@link ChannelBuffers#buffer(int)} etc when * an empty buffer is requested. * *

Note: For backwards compatibility, this class extends {@link BigEndianHeapChannelBuffer}. * However, it never makes any writes to the reader and writer indices, which avoids contention * when the singleton instance is used concurrently. */ public class EmptyChannelBuffer extends BigEndianHeapChannelBuffer { private static final byte[] BUFFER = {}; EmptyChannelBuffer() { super(BUFFER); } @Override public void clear() { } @Override public void readerIndex(int readerIndex) { if (readerIndex != 0) { throw new IndexOutOfBoundsException("Invalid readerIndex: " + readerIndex + " - Maximum is 0"); } } @Override public void writerIndex(int writerIndex) { if (writerIndex != 0) { throw new IndexOutOfBoundsException("Invalid writerIndex: " + writerIndex + " - Maximum is 0"); } } @Override public void setIndex(int readerIndex, int writerIndex) { if (writerIndex != 0 || readerIndex != 0) { throw new IndexOutOfBoundsException("Invalid writerIndex: " + writerIndex + " - Maximum is " + readerIndex + " or " + capacity()); } } @Override public void markReaderIndex() { } @Override public void resetReaderIndex() { } @Override public void markWriterIndex() { } @Override public void resetWriterIndex() { } @Override public void discardReadBytes() { } @Override public ChannelBuffer readBytes(int length) { checkReadableBytes(length); return this; } @Override public ChannelBuffer readSlice(int length) { checkReadableBytes(length); return this; } @Override public void readBytes(byte[] dst, int dstIndex, int length) { checkReadableBytes(length); } @Override public void readBytes(byte[] dst) { checkReadableBytes(dst.length); } @Override public void readBytes(ChannelBuffer dst) { checkReadableBytes(dst.writableBytes()); } @Override public void readBytes(ChannelBuffer dst, int length) { checkReadableBytes(length); } @Override public void readBytes(ChannelBuffer dst, int dstIndex, int length) { checkReadableBytes(length); } @Override public void readBytes(ByteBuffer dst) { checkReadableBytes(dst.remaining()); } @Override public int readBytes(GatheringByteChannel out, int length) throws IOException { checkReadableBytes(length); return 0; } @Override public void readBytes(OutputStream out, int length) throws IOException { checkReadableBytes(length); } @Override public void skipBytes(int length) { checkReadableBytes(length); } @Override public void writeBytes(byte[] src, int srcIndex, int length) { checkWritableBytes(length); } @Override public void writeBytes(ChannelBuffer src, int length) { checkWritableBytes(length); } @Override public void writeBytes(ChannelBuffer src, int srcIndex, int length) { checkWritableBytes(length); } @Override public void writeBytes(ByteBuffer src) { checkWritableBytes(src.remaining()); } @Override public int writeBytes(InputStream in, int length) throws IOException { checkWritableBytes(length); return 0; } @Override public int writeBytes(ScatteringByteChannel in, int length) throws IOException { checkWritableBytes(length); return 0; } @Override public void writeZero(int length) { checkWritableBytes(length); } /** * Throws an {@link IndexOutOfBoundsException} the length is not 0. */ private void checkWritableBytes(int length) { if (length == 0) { return; } if (length > 0) { throw new IndexOutOfBoundsException("Writable bytes exceeded - Need " + length + ", maximum is " + 0); } else { throw new IndexOutOfBoundsException("length < 0"); } } /** * Throws an {@link IndexOutOfBoundsException} the length is not 0. */ protected void checkReadableBytes(int length) { if (length == 0) { return; } if (length > 0) { throw new IndexOutOfBoundsException("Not enough readable bytes - Need " + length + ", maximum is " + readableBytes()); } else { throw new IndexOutOfBoundsException("length < 0"); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/HeapChannelBuffer.java000066400000000000000000000140741225554127700302210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A skeletal implementation for Java heap buffers. */ public abstract class HeapChannelBuffer extends AbstractChannelBuffer { /** * The underlying heap byte array that this buffer is wrapping. */ protected final byte[] array; /** * Creates a new heap buffer with a newly allocated byte array. * * @param length the length of the new byte array */ protected HeapChannelBuffer(int length) { this(new byte[length], 0, 0); } /** * Creates a new heap buffer with an existing byte array. * * @param array the byte array to wrap */ protected HeapChannelBuffer(byte[] array) { this(array, 0, array.length); } /** * Creates a new heap buffer with an existing byte array. * * @param array the byte array to wrap * @param readerIndex the initial reader index of this buffer * @param writerIndex the initial writer index of this buffer */ protected HeapChannelBuffer(byte[] array, int readerIndex, int writerIndex) { if (array == null) { throw new NullPointerException("array"); } this.array = array; setIndex(readerIndex, writerIndex); } public boolean isDirect() { return false; } public int capacity() { return array.length; } public boolean hasArray() { return true; } public byte[] array() { return array; } public int arrayOffset() { return 0; } public byte getByte(int index) { return array[index]; } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { if (dst instanceof HeapChannelBuffer) { getBytes(index, ((HeapChannelBuffer) dst).array, dstIndex, length); } else { dst.setBytes(dstIndex, array, index, length); } } public void getBytes(int index, byte[] dst, int dstIndex, int length) { System.arraycopy(array, index, dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { dst.put(array, index, Math.min(capacity() - index, dst.remaining())); } public void getBytes(int index, OutputStream out, int length) throws IOException { out.write(array, index, length); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { return out.write(ByteBuffer.wrap(array, index, length)); } public void setByte(int index, int value) { array[index] = (byte) value; } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { if (src instanceof HeapChannelBuffer) { setBytes(index, ((HeapChannelBuffer) src).array, srcIndex, length); } else { src.getBytes(srcIndex, array, index, length); } } public void setBytes(int index, byte[] src, int srcIndex, int length) { System.arraycopy(src, srcIndex, array, index, length); } public void setBytes(int index, ByteBuffer src) { src.get(array, index, src.remaining()); } public int setBytes(int index, InputStream in, int length) throws IOException { int readBytes = 0; do { int localReadBytes = in.read(array, index, length); if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } readBytes += localReadBytes; index += localReadBytes; length -= localReadBytes; } while (length > 0); return readBytes; } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { ByteBuffer buf = ByteBuffer.wrap(array, index, length); int readBytes = 0; do { int localReadBytes; try { localReadBytes = in.read(buf); } catch (ClosedChannelException e) { localReadBytes = -1; } if (localReadBytes < 0) { if (readBytes == 0) { return -1; } else { break; } } if (localReadBytes == 0) { break; } readBytes += localReadBytes; } while (readBytes < length); return readBytes; } public ChannelBuffer slice(int index, int length) { if (index == 0) { if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } if (length == array.length) { ChannelBuffer slice = duplicate(); slice.setIndex(0, length); return slice; } else { return new TruncatedChannelBuffer(this, length); } } else { if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } return new SlicedChannelBuffer(this, index, length); } } public ByteBuffer toByteBuffer(int index, int length) { return ByteBuffer.wrap(array, index, length).order(order()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/HeapChannelBufferFactory.java000066400000000000000000000056771225554127700315620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * A {@link ChannelBufferFactory} which merely allocates a heap buffer with * the specified capacity. {@link HeapChannelBufferFactory} should perform * very well in most situations because it relies on the JVM garbage collector, * which is highly optimized for heap allocation. */ public class HeapChannelBufferFactory extends AbstractChannelBufferFactory { private static final HeapChannelBufferFactory INSTANCE_BE = new HeapChannelBufferFactory(ByteOrder.BIG_ENDIAN); private static final HeapChannelBufferFactory INSTANCE_LE = new HeapChannelBufferFactory(ByteOrder.LITTLE_ENDIAN); public static ChannelBufferFactory getInstance() { return INSTANCE_BE; } public static ChannelBufferFactory getInstance(ByteOrder endianness) { if (endianness == ByteOrder.BIG_ENDIAN) { return INSTANCE_BE; } else if (endianness == ByteOrder.LITTLE_ENDIAN) { return INSTANCE_LE; } else if (endianness == null) { throw new NullPointerException("endianness"); } else { throw new IllegalStateException("Should not reach here"); } } /** * Creates a new factory whose default {@link ByteOrder} is * {@link ByteOrder#BIG_ENDIAN}. */ public HeapChannelBufferFactory() { } /** * Creates a new factory with the specified default {@link ByteOrder}. * * @param defaultOrder the default {@link ByteOrder} of this factory */ public HeapChannelBufferFactory(ByteOrder defaultOrder) { super(defaultOrder); } public ChannelBuffer getBuffer(ByteOrder order, int capacity) { return ChannelBuffers.buffer(order, capacity); } public ChannelBuffer getBuffer(ByteOrder order, byte[] array, int offset, int length) { return ChannelBuffers.wrappedBuffer(order, array, offset, length); } public ChannelBuffer getBuffer(ByteBuffer nioBuffer) { if (nioBuffer.hasArray()) { return ChannelBuffers.wrappedBuffer(nioBuffer); } ChannelBuffer buf = getBuffer(nioBuffer.order(), nioBuffer.remaining()); int pos = nioBuffer.position(); buf.writeBytes(nioBuffer); nioBuffer.position(pos); return buf; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/LittleEndianHeapChannelBuffer.java000066400000000000000000000105761225554127700325210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.nio.ByteOrder; /** * A little-endian Java heap buffer. It is recommended to use {@link ChannelBuffers#buffer(ByteOrder, int)} * and {@link ChannelBuffers#wrappedBuffer(ByteOrder, byte[])} instead of * calling the constructor explicitly. */ public class LittleEndianHeapChannelBuffer extends HeapChannelBuffer { /** * Creates a new little-endian heap buffer with a newly allocated byte array. * * @param length the length of the new byte array */ public LittleEndianHeapChannelBuffer(int length) { super(length); } /** * Creates a new little-endian heap buffer with an existing byte array. * * @param array the byte array to wrap */ public LittleEndianHeapChannelBuffer(byte[] array) { super(array); } private LittleEndianHeapChannelBuffer(byte[] array, int readerIndex, int writerIndex) { super(array, readerIndex, writerIndex); } public ChannelBufferFactory factory() { return HeapChannelBufferFactory.getInstance(ByteOrder.LITTLE_ENDIAN); } public ByteOrder order() { return ByteOrder.LITTLE_ENDIAN; } public short getShort(int index) { return (short) (array[index] & 0xFF | array[index + 1] << 8); } public int getUnsignedMedium(int index) { return array[index] & 0xff | (array[index + 1] & 0xff) << 8 | (array[index + 2] & 0xff) << 16; } public int getInt(int index) { return array[index] & 0xff | (array[index + 1] & 0xff) << 8 | (array[index + 2] & 0xff) << 16 | (array[index + 3] & 0xff) << 24; } public long getLong(int index) { return (long) array[index] & 0xff | ((long) array[index + 1] & 0xff) << 8 | ((long) array[index + 2] & 0xff) << 16 | ((long) array[index + 3] & 0xff) << 24 | ((long) array[index + 4] & 0xff) << 32 | ((long) array[index + 5] & 0xff) << 40 | ((long) array[index + 6] & 0xff) << 48 | ((long) array[index + 7] & 0xff) << 56; } public void setShort(int index, int value) { array[index] = (byte) value; array[index + 1] = (byte) (value >>> 8); } public void setMedium(int index, int value) { array[index] = (byte) value; array[index + 1] = (byte) (value >>> 8); array[index + 2] = (byte) (value >>> 16); } public void setInt(int index, int value) { array[index] = (byte) value; array[index + 1] = (byte) (value >>> 8); array[index + 2] = (byte) (value >>> 16); array[index + 3] = (byte) (value >>> 24); } public void setLong(int index, long value) { array[index] = (byte) value; array[index + 1] = (byte) (value >>> 8); array[index + 2] = (byte) (value >>> 16); array[index + 3] = (byte) (value >>> 24); array[index + 4] = (byte) (value >>> 32); array[index + 5] = (byte) (value >>> 40); array[index + 6] = (byte) (value >>> 48); array[index + 7] = (byte) (value >>> 56); } public ChannelBuffer duplicate() { return new LittleEndianHeapChannelBuffer(array, readerIndex(), writerIndex()); } public ChannelBuffer copy(int index, int length) { if (index < 0 || length < 0 || index + length > array.length) { throw new IndexOutOfBoundsException("Too many bytes to copy - Need " + (index + length) + ", maximum is " + array.length); } byte[] copiedArray = new byte[length]; System.arraycopy(array, index, copiedArray, 0, length); return new LittleEndianHeapChannelBuffer(copiedArray); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/ReadOnlyChannelBuffer.java000066400000000000000000000125261225554127700310610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ReadOnlyBufferException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A derived buffer which forbids any write requests to its parent. It is * recommended to use {@link ChannelBuffers#unmodifiableBuffer(ChannelBuffer)} * instead of calling the constructor explicitly. */ public class ReadOnlyChannelBuffer extends AbstractChannelBuffer implements WrappedChannelBuffer { private final ChannelBuffer buffer; public ReadOnlyChannelBuffer(ChannelBuffer buffer) { if (buffer == null) { throw new NullPointerException("buffer"); } this.buffer = buffer; setIndex(buffer.readerIndex(), buffer.writerIndex()); } private ReadOnlyChannelBuffer(ReadOnlyChannelBuffer buffer) { this.buffer = buffer.buffer; setIndex(buffer.readerIndex(), buffer.writerIndex()); } public ChannelBuffer unwrap() { return buffer; } public ChannelBufferFactory factory() { return buffer.factory(); } public ByteOrder order() { return buffer.order(); } public boolean isDirect() { return buffer.isDirect(); } public boolean hasArray() { return false; } public byte[] array() { throw new ReadOnlyBufferException(); } public int arrayOffset() { throw new ReadOnlyBufferException(); } @Override public void discardReadBytes() { throw new ReadOnlyBufferException(); } public void setByte(int index, int value) { throw new ReadOnlyBufferException(); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { throw new ReadOnlyBufferException(); } public void setBytes(int index, byte[] src, int srcIndex, int length) { throw new ReadOnlyBufferException(); } public void setBytes(int index, ByteBuffer src) { throw new ReadOnlyBufferException(); } public void setShort(int index, int value) { throw new ReadOnlyBufferException(); } public void setMedium(int index, int value) { throw new ReadOnlyBufferException(); } public void setInt(int index, int value) { throw new ReadOnlyBufferException(); } public void setLong(int index, long value) { throw new ReadOnlyBufferException(); } public int setBytes(int index, InputStream in, int length) throws IOException { throw new ReadOnlyBufferException(); } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { throw new ReadOnlyBufferException(); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { return buffer.getBytes(index, out, length); } public void getBytes(int index, OutputStream out, int length) throws IOException { buffer.getBytes(index, out, length); } public void getBytes(int index, byte[] dst, int dstIndex, int length) { buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { buffer.getBytes(index, dst); } public ChannelBuffer duplicate() { return new ReadOnlyChannelBuffer(this); } public ChannelBuffer copy(int index, int length) { return buffer.copy(index, length); } public ChannelBuffer slice(int index, int length) { return new ReadOnlyChannelBuffer(buffer.slice(index, length)); } public byte getByte(int index) { return buffer.getByte(index); } public short getShort(int index) { return buffer.getShort(index); } public int getUnsignedMedium(int index) { return buffer.getUnsignedMedium(index); } public int getInt(int index) { return buffer.getInt(index); } public long getLong(int index) { return buffer.getLong(index); } public ByteBuffer toByteBuffer(int index, int length) { return buffer.toByteBuffer(index, length).asReadOnlyBuffer(); } @Override public ByteBuffer[] toByteBuffers(int index, int length) { ByteBuffer[] bufs = buffer.toByteBuffers(index, length); for (int i = 0; i < bufs.length; i ++) { bufs[i] = bufs[i].asReadOnlyBuffer(); } return bufs; } public int capacity() { return buffer.capacity(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/SlicedChannelBuffer.java000066400000000000000000000162261225554127700305500ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A derived buffer which exposes its parent's sub-region only. It is * recommended to use {@link ChannelBuffer#slice()} and * {@link ChannelBuffer#slice(int, int)} instead of calling the constructor * explicitly. */ public class SlicedChannelBuffer extends AbstractChannelBuffer implements WrappedChannelBuffer { private final ChannelBuffer buffer; private final int adjustment; private final int length; public SlicedChannelBuffer(ChannelBuffer buffer, int index, int length) { if (index < 0 || index > buffer.capacity()) { throw new IndexOutOfBoundsException("Invalid index of " + index + ", maximum is " + buffer.capacity()); } if (index + length > buffer.capacity()) { throw new IndexOutOfBoundsException("Invalid combined index of " + (index + length) + ", maximum is " + buffer.capacity()); } this.buffer = buffer; adjustment = index; this.length = length; writerIndex(length); } public ChannelBuffer unwrap() { return buffer; } public ChannelBufferFactory factory() { return buffer.factory(); } public ByteOrder order() { return buffer.order(); } public boolean isDirect() { return buffer.isDirect(); } public int capacity() { return length; } public boolean hasArray() { return buffer.hasArray(); } public byte[] array() { return buffer.array(); } public int arrayOffset() { return buffer.arrayOffset() + adjustment; } public byte getByte(int index) { checkIndex(index); return buffer.getByte(index + adjustment); } public short getShort(int index) { checkIndex(index, 2); return buffer.getShort(index + adjustment); } public int getUnsignedMedium(int index) { checkIndex(index, 3); return buffer.getUnsignedMedium(index + adjustment); } public int getInt(int index) { checkIndex(index, 4); return buffer.getInt(index + adjustment); } public long getLong(int index) { checkIndex(index, 8); return buffer.getLong(index + adjustment); } public ChannelBuffer duplicate() { ChannelBuffer duplicate = new SlicedChannelBuffer(buffer, adjustment, length); duplicate.setIndex(readerIndex(), writerIndex()); return duplicate; } public ChannelBuffer copy(int index, int length) { checkIndex(index, length); return buffer.copy(index + adjustment, length); } public ChannelBuffer slice(int index, int length) { checkIndex(index, length); if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } return new SlicedChannelBuffer(buffer, index + adjustment, length); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { checkIndex(index, length); buffer.getBytes(index + adjustment, dst, dstIndex, length); } public void getBytes(int index, byte[] dst, int dstIndex, int length) { checkIndex(index, length); buffer.getBytes(index + adjustment, dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { checkIndex(index, dst.remaining()); buffer.getBytes(index + adjustment, dst); } public void setByte(int index, int value) { checkIndex(index); buffer.setByte(index + adjustment, value); } public void setShort(int index, int value) { checkIndex(index, 2); buffer.setShort(index + adjustment, value); } public void setMedium(int index, int value) { checkIndex(index, 3); buffer.setMedium(index + adjustment, value); } public void setInt(int index, int value) { checkIndex(index, 4); buffer.setInt(index + adjustment, value); } public void setLong(int index, long value) { checkIndex(index, 8); buffer.setLong(index + adjustment, value); } public void setBytes(int index, byte[] src, int srcIndex, int length) { checkIndex(index, length); buffer.setBytes(index + adjustment, src, srcIndex, length); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { checkIndex(index, length); buffer.setBytes(index + adjustment, src, srcIndex, length); } public void setBytes(int index, ByteBuffer src) { checkIndex(index, src.remaining()); buffer.setBytes(index + adjustment, src); } public void getBytes(int index, OutputStream out, int length) throws IOException { checkIndex(index, length); buffer.getBytes(index + adjustment, out, length); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { checkIndex(index, length); return buffer.getBytes(index + adjustment, out, length); } public int setBytes(int index, InputStream in, int length) throws IOException { checkIndex(index, length); return buffer.setBytes(index + adjustment, in, length); } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { checkIndex(index, length); return buffer.setBytes(index + adjustment, in, length); } public ByteBuffer toByteBuffer(int index, int length) { checkIndex(index, length); return buffer.toByteBuffer(index + adjustment, length); } private void checkIndex(int index) { if (index < 0 || index >= capacity()) { throw new IndexOutOfBoundsException("Invalid index: " + index + ", maximum is " + capacity()); } } private void checkIndex(int startIndex, int length) { if (length < 0) { throw new IllegalArgumentException( "length is negative: " + length); } if (startIndex < 0) { throw new IndexOutOfBoundsException("startIndex cannot be negative"); } if (startIndex + length > capacity()) { throw new IndexOutOfBoundsException("Index too big - Bytes needed: " + (startIndex + length) + ", maximum is " + capacity()); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/TruncatedChannelBuffer.java000066400000000000000000000146521225554127700312770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * A derived buffer which hides its parent's tail data beyond a certain index. * It is recommended to use {@link ChannelBuffer#slice()} and * {@link ChannelBuffer#slice(int, int)} instead of calling the constructor * explicitly. */ public class TruncatedChannelBuffer extends AbstractChannelBuffer implements WrappedChannelBuffer { private final ChannelBuffer buffer; private final int length; public TruncatedChannelBuffer(ChannelBuffer buffer, int length) { if (length > buffer.capacity()) { throw new IndexOutOfBoundsException("Length is too large, got " + length + " but can't go higher than " + buffer.capacity()); } this.buffer = buffer; this.length = length; writerIndex(length); } public ChannelBuffer unwrap() { return buffer; } public ChannelBufferFactory factory() { return buffer.factory(); } public ByteOrder order() { return buffer.order(); } public boolean isDirect() { return buffer.isDirect(); } public int capacity() { return length; } public boolean hasArray() { return buffer.hasArray(); } public byte[] array() { return buffer.array(); } public int arrayOffset() { return buffer.arrayOffset(); } public byte getByte(int index) { checkIndex(index); return buffer.getByte(index); } public short getShort(int index) { checkIndex(index, 2); return buffer.getShort(index); } public int getUnsignedMedium(int index) { checkIndex(index, 3); return buffer.getUnsignedMedium(index); } public int getInt(int index) { checkIndex(index, 4); return buffer.getInt(index); } public long getLong(int index) { checkIndex(index, 8); return buffer.getLong(index); } public ChannelBuffer duplicate() { ChannelBuffer duplicate = new TruncatedChannelBuffer(buffer, length); duplicate.setIndex(readerIndex(), writerIndex()); return duplicate; } public ChannelBuffer copy(int index, int length) { checkIndex(index, length); return buffer.copy(index, length); } public ChannelBuffer slice(int index, int length) { checkIndex(index, length); if (length == 0) { return ChannelBuffers.EMPTY_BUFFER; } return buffer.slice(index, length); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { checkIndex(index, length); buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, byte[] dst, int dstIndex, int length) { checkIndex(index, length); buffer.getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ByteBuffer dst) { checkIndex(index, dst.remaining()); buffer.getBytes(index, dst); } public void setByte(int index, int value) { checkIndex(index); buffer.setByte(index, value); } public void setShort(int index, int value) { checkIndex(index, 2); buffer.setShort(index, value); } public void setMedium(int index, int value) { checkIndex(index, 3); buffer.setMedium(index, value); } public void setInt(int index, int value) { checkIndex(index, 4); buffer.setInt(index, value); } public void setLong(int index, long value) { checkIndex(index, 8); buffer.setLong(index, value); } public void setBytes(int index, byte[] src, int srcIndex, int length) { checkIndex(index, length); buffer.setBytes(index, src, srcIndex, length); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { checkIndex(index, length); buffer.setBytes(index, src, srcIndex, length); } public void setBytes(int index, ByteBuffer src) { checkIndex(index, src.remaining()); buffer.setBytes(index, src); } public void getBytes(int index, OutputStream out, int length) throws IOException { checkIndex(index, length); buffer.getBytes(index, out, length); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { checkIndex(index, length); return buffer.getBytes(index, out, length); } public int setBytes(int index, InputStream in, int length) throws IOException { checkIndex(index, length); return buffer.setBytes(index, in, length); } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { checkIndex(index, length); return buffer.setBytes(index, in, length); } public ByteBuffer toByteBuffer(int index, int length) { checkIndex(index, length); return buffer.toByteBuffer(index, length); } private void checkIndex(int index) { if (index < 0 || index >= capacity()) { throw new IndexOutOfBoundsException("Invalid index of " + index + ", maximum is " + capacity()); } } private void checkIndex(int index, int length) { if (length < 0) { throw new IllegalArgumentException( "length is negative: " + length); } if (index + length > capacity()) { throw new IndexOutOfBoundsException("Invalid index of " + (index + length) + ", maximum is " + capacity()); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/WrappedChannelBuffer.java000066400000000000000000000017521225554127700307450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; /** * The common interface for buffer wrappers and derived buffers. Most users won't * need to use this interface. It is used internally in most cases. */ public interface WrappedChannelBuffer extends ChannelBuffer { /** * Returns this buffer's parent that this buffer is wrapping. */ ChannelBuffer unwrap(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/buffer/package-info.java000066400000000000000000000144451225554127700272470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Abstraction of a byte buffer - the fundamental data structure * to represent a low-level binary and text message. * * Netty uses its own buffer API instead of NIO {@link java.nio.ByteBuffer} to * represent a sequence of bytes. This approach has significant advantage over * using {@link java.nio.ByteBuffer}. Netty's new buffer type, * {@link org.jboss.netty.buffer.ChannelBuffer}, has been designed from ground * up to address the problems of {@link java.nio.ByteBuffer} and to meet the * daily needs of network application developers. To list a few cool features: *

    *
  • You can define your buffer type if necessary.
  • *
  • Transparent zero copy is achieved by built-in composite buffer type.
  • *
  • A dynamic buffer type is provided out-of-the-box, whose capacity is * expanded on demand, just like {@link java.lang.StringBuffer}.
  • *
  • There's no need to call the {@code flip()} method anymore.
  • *
  • It is often faster than {@link java.nio.ByteBuffer}.
  • *
* *

Extensibility

* * {@link org.jboss.netty.buffer.ChannelBuffer} has rich set of operations * optimized for rapid protocol implementation. For example, * {@link org.jboss.netty.buffer.ChannelBuffer} provides various operations * for accessing unsigned values and strings and searching for certain byte * sequence in a buffer. You can also extend or wrap existing buffer type * to add convenient accessors. The custom buffer type still implements * {@link org.jboss.netty.buffer.ChannelBuffer} interface rather than * introducing an incompatible type. * *

Transparent Zero Copy

* * To lift up the performance of a network application to the extreme, you need * to reduce the number of memory copy operation. You might have a set of * buffers that could be sliced and combined to compose a whole message. Netty * provides a composite buffer which allows you to create a new buffer from the * arbitrary number of existing buffers with no memory copy. For example, a * message could be composed of two parts; header and body. In a modularized * application, the two parts could be produced by different modules and * assembled later when the message is sent out. *
 * +--------+----------+
 * | header |   body   |
 * +--------+----------+
 * 
* If {@link java.nio.ByteBuffer} were used, you would have to create a new big * buffer and copy the two parts into the new buffer. Alternatively, you can * perform a gathering write operation in NIO, but it restricts you to represent * the composite of buffers as an array of {@link java.nio.ByteBuffer}s rather * than a single buffer, breaking the abstraction and introducing complicated * state management. Moreover, it's of no use if you are not going to read or * write from an NIO channel. *
 * // The composite type is incompatible with the component type.
 * ByteBuffer[] message = new ByteBuffer[] { header, body };
 * 
* By contrast, {@link org.jboss.netty.buffer.ChannelBuffer} does not have such * caveats because it is fully extensible and has a built-in composite buffer * type. *
 * // The composite type is compatible with the component type.
 * ChannelBuffer message = ChannelBuffers.wrappedBuffer(header, body);
 *
 * // Therefore, you can even create a composite by mixing a composite and an
 * // ordinary buffer.
 * ChannelBuffer messageWithFooter = ChannelBuffers.wrappedBuffer(message, footer);
 *
 * // Because the composite is still a ChannelBuffer, you can access its content
 * // easily, and the accessor method will behave just like it's a single buffer
 * // even if the region you want to access spans over multiple components.  The
 * // unsigned integer being read here is located across body and footer.
 * messageWithFooter.getUnsignedInt(
 *     messageWithFooter.readableBytes() - footer.readableBytes() - 1);
 * 
* *

Automatic Capacity Extension

* * Many protocols define variable length messages, which means there's no way to * determine the length of a message until you construct the message or it is * difficult and inconvenient to calculate the length precisely. It is just * like when you build a {@link java.lang.String}. You often estimate the length * of the resulting string and let {@link java.lang.StringBuffer} expand itself * on demand. Netty allows you to do the same via a dynamic buffer * which is created by the * {@link org.jboss.netty.buffer.ChannelBuffers#dynamicBuffer()} method. *
 * // A new dynamic buffer is created.  Internally, the actual buffer is created
 * // lazily to avoid potentially wasted memory space.
 * ChannelBuffer b = ChannelBuffers.dynamicBuffer(4);
 *
 * // When the first write attempt is made, the internal buffer is created with
 * // the specified initial capacity (4).
 * b.writeByte('1');
 *
 * b.writeByte('2');
 * b.writeByte('3');
 * b.writeByte('4');
 *
 * // When the number of written bytes exceeds the initial capacity (4), the
 * // internal buffer is reallocated automatically with a larger capacity.
 * b.writeByte('5');
 * 
* *

Better Performance

* * Most frequently used buffer implementation of * {@link org.jboss.netty.buffer.ChannelBuffer} is a very thin wrapper of a * byte array (i.e. {@code byte[]}). Unlike {@link java.nio.ByteBuffer}, it has * no complicated boundary check and index compensation, and therefore it is * easier for a JVM to optimize the buffer access. More complicated buffer * implementation is used only for sliced or composite buffers, and it performs * as well as {@link java.nio.ByteBuffer}. * * @apiviz.landmark * @apiviz.exclude ^java\.lang\. * @apiviz.exclude ^java\.io\.[^\.]+Stream$ */ package org.jboss.netty.buffer; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/000077500000000000000000000000001225554127700242075ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/AbstractChannel.java000066400000000000000000000244451225554127700301170ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.util.internal.ConcurrentHashMap; import java.net.SocketAddress; import java.util.Random; import java.util.concurrent.ConcurrentMap; /** * A skeletal {@link Channel} implementation. */ public abstract class AbstractChannel implements Channel { static final ConcurrentMap allChannels = new ConcurrentHashMap(); private static final Random random = new Random(); private static Integer allocateId(Channel channel) { Integer id = random.nextInt(); for (;;) { // Loop until a unique ID is acquired. // It should be found in one loop practically. if (allChannels.putIfAbsent(id, channel) == null) { // Successfully acquired. return id; } else { // Taken by other channel at almost the same moment. id = id.intValue() + 1; } } } private final Integer id; private final Channel parent; private final ChannelFactory factory; private final ChannelPipeline pipeline; private final ChannelFuture succeededFuture = new SucceededChannelFuture(this); private final ChannelCloseFuture closeFuture = new ChannelCloseFuture(); private volatile int interestOps = OP_READ; /** Cache for the string representation of this channel */ private boolean strValConnected; private String strVal; private volatile Object attachment; /** * Creates a new instance. * * @param parent * the parent of this channel. {@code null} if there's no parent. * @param factory * the factory which created this channel * @param pipeline * the pipeline which is going to be attached to this channel * @param sink * the sink which will receive downstream events from the pipeline * and send upstream events to the pipeline */ protected AbstractChannel( Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { this.parent = parent; this.factory = factory; this.pipeline = pipeline; id = allocateId(this); pipeline.attach(this, sink); } /** * (Internal use only) Creates a new temporary instance with the specified * ID. * * @param parent * the parent of this channel. {@code null} if there's no parent. * @param factory * the factory which created this channel * @param pipeline * the pipeline which is going to be attached to this channel * @param sink * the sink which will receive downstream events from the pipeline * and send upstream events to the pipeline */ protected AbstractChannel( Integer id, Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { this.id = id; this.parent = parent; this.factory = factory; this.pipeline = pipeline; pipeline.attach(this, sink); } public final Integer getId() { return id; } public Channel getParent() { return parent; } public ChannelFactory getFactory() { return factory; } public ChannelPipeline getPipeline() { return pipeline; } /** * Returns the cached {@link SucceededChannelFuture} instance. */ protected ChannelFuture getSucceededFuture() { return succeededFuture; } /** * Returns the {@link FailedChannelFuture} whose cause is an * {@link UnsupportedOperationException}. */ protected ChannelFuture getUnsupportedOperationFuture() { return new FailedChannelFuture(this, new UnsupportedOperationException()); } /** * Returns the ID of this channel. */ @Override public final int hashCode() { return id; } /** * Returns {@code true} if and only if the specified object is identical * with this channel (i.e: {@code this == o}). */ @Override public final boolean equals(Object o) { return this == o; } /** * Compares the {@linkplain #getId() ID} of the two channels. */ public final int compareTo(Channel o) { return getId().compareTo(o.getId()); } public boolean isOpen() { return !closeFuture.isDone(); } /** * Marks this channel as closed. This method is intended to be called by * an internal component - please do not call it unless you know what you * are doing. * * @return {@code true} if and only if this channel was not marked as * closed yet */ protected boolean setClosed() { // Deallocate the current channel's ID from allChannels so that other // new channels can use it. allChannels.remove(id); return closeFuture.setClosed(); } public ChannelFuture bind(SocketAddress localAddress) { return Channels.bind(this, localAddress); } public ChannelFuture unbind() { return Channels.unbind(this); } public ChannelFuture close() { ChannelFuture returnedCloseFuture = Channels.close(this); assert closeFuture == returnedCloseFuture; return closeFuture; } public ChannelFuture getCloseFuture() { return closeFuture; } public ChannelFuture connect(SocketAddress remoteAddress) { return Channels.connect(this, remoteAddress); } public ChannelFuture disconnect() { return Channels.disconnect(this); } public int getInterestOps() { return interestOps; } public ChannelFuture setInterestOps(int interestOps) { return Channels.setInterestOps(this, interestOps); } /** * Sets the {@link #getInterestOps() interestOps} property of this channel * immediately. This method is intended to be called by an internal * component - please do not call it unless you know what you are doing. */ protected void setInterestOpsNow(int interestOps) { this.interestOps = interestOps; } public boolean isReadable() { return (getInterestOps() & OP_READ) != 0; } public boolean isWritable() { return (getInterestOps() & OP_WRITE) == 0; } public ChannelFuture setReadable(boolean readable) { if (readable) { return setInterestOps(getInterestOps() | OP_READ); } else { return setInterestOps(getInterestOps() & ~OP_READ); } } public ChannelFuture write(Object message) { return Channels.write(this, message); } public ChannelFuture write(Object message, SocketAddress remoteAddress) { return Channels.write(this, message, remoteAddress); } public Object getAttachment() { return attachment; } public void setAttachment(Object attachment) { this.attachment = attachment; } /** * Returns the {@link String} representation of this channel. The returned * string contains the {@linkplain #getId() ID}, {@linkplain #getLocalAddress() local address}, * and {@linkplain #getRemoteAddress() remote address} of this channel for * easier identification. */ @Override public String toString() { boolean connected = isConnected(); if (strValConnected == connected && strVal != null) { return strVal; } StringBuilder buf = new StringBuilder(128); buf.append("[id: 0x"); buf.append(getIdString()); SocketAddress localAddress = getLocalAddress(); SocketAddress remoteAddress = getRemoteAddress(); if (remoteAddress != null) { buf.append(", "); if (getParent() == null) { buf.append(localAddress); buf.append(connected? " => " : " :> "); buf.append(remoteAddress); } else { buf.append(remoteAddress); buf.append(connected? " => " : " :> "); buf.append(localAddress); } } else if (localAddress != null) { buf.append(", "); buf.append(localAddress); } buf.append(']'); String strVal = buf.toString(); this.strVal = strVal; strValConnected = connected; return strVal; } private String getIdString() { String answer = Integer.toHexString(id.intValue()); switch (answer.length()) { case 0: answer = "00000000"; break; case 1: answer = "0000000" + answer; break; case 2: answer = "000000" + answer; break; case 3: answer = "00000" + answer; break; case 4: answer = "0000" + answer; break; case 5: answer = "000" + answer; break; case 6: answer = "00" + answer; break; case 7: answer = '0' + answer; break; } return answer; } private final class ChannelCloseFuture extends DefaultChannelFuture { public ChannelCloseFuture() { super(AbstractChannel.this, false); } @Override public boolean setSuccess() { // User is not supposed to call this method - ignore silently. return false; } @Override public boolean setFailure(Throwable cause) { // User is not supposed to call this method - ignore silently. return false; } boolean setClosed() { return super.setSuccess(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/AbstractChannelSink.java000066400000000000000000000051411225554127700307340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.jboss.netty.channel.Channels.*; /** * A skeletal {@link ChannelSink} implementation. */ public abstract class AbstractChannelSink implements ChannelSink { /** * Creates a new instance. */ protected AbstractChannelSink() { } /** * Sends an {@link ExceptionEvent} upstream with the specified * {@code cause}. * * @param event the {@link ChannelEvent} which caused a * {@link ChannelHandler} to raise an exception * @param cause the exception raised by a {@link ChannelHandler} */ public void exceptionCaught(ChannelPipeline pipeline, ChannelEvent event, ChannelPipelineException cause) throws Exception { Throwable actualCause = cause.getCause(); if (actualCause == null) { actualCause = cause; } if (isFireExceptionCaughtLater(event, actualCause)) { fireExceptionCaughtLater(event.getChannel(), actualCause); } else { fireExceptionCaught(event.getChannel(), actualCause); } } /** * Returns {@code true} if and only if the specified {@code actualCause}, which was raised while * handling the specified {@code event}, must trigger an {@code exceptionCaught()} event in * an I/O thread. * * @param event the event which raised exception * @param actualCause the raised exception */ protected boolean isFireExceptionCaughtLater(ChannelEvent event, Throwable actualCause) { return false; } /** * This implementation just directly call {@link Runnable#run()}. * Sub-classes should override this if they can handle it in a better way */ public ChannelFuture execute(ChannelPipeline pipeline, Runnable task) { try { task.run(); return succeededFuture(pipeline.getChannel()); } catch (Throwable t) { return failedFuture(pipeline.getChannel(), t); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/AbstractServerChannel.java000066400000000000000000000052351225554127700313020ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; /** * A skeletal server-side {@link Channel} implementation. A server-side * {@link Channel} does not allow the following operations: *
    *
  • {@link #connect(SocketAddress)}
  • *
  • {@link #disconnect()}
  • *
  • {@link #getInterestOps()}
  • *
  • {@link #setInterestOps(int)}
  • *
  • {@link #write(Object)}
  • *
  • {@link #write(Object, SocketAddress)}
  • *
  • and the shortcut methods which calls the methods mentioned above *
*/ public abstract class AbstractServerChannel extends AbstractChannel implements ServerChannel { /** * Creates a new instance. * * @param factory * the factory which created this channel * @param pipeline * the pipeline which is going to be attached to this channel * @param sink * the sink which will receive downstream events from the pipeline * and send upstream events to the pipeline */ protected AbstractServerChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(null, factory, pipeline, sink); } @Override public ChannelFuture connect(SocketAddress remoteAddress) { return getUnsupportedOperationFuture(); } @Override public ChannelFuture disconnect() { return getUnsupportedOperationFuture(); } @Override public int getInterestOps() { return OP_NONE; } @Override public ChannelFuture setInterestOps(int interestOps) { return getUnsupportedOperationFuture(); } @Override protected void setInterestOpsNow(int interestOps) { // Ignore. } @Override public ChannelFuture write(Object message) { return getUnsupportedOperationFuture(); } @Override public ChannelFuture write(Object message, SocketAddress remoteAddress) { return getUnsupportedOperationFuture(); } public boolean isConnected() { return false; } } AdaptiveReceiveBufferSizePredictor.java000066400000000000000000000125501225554127700336770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.util.ArrayList; import java.util.List; /** * The {@link ReceiveBufferSizePredictor} that automatically increases and * decreases the predicted buffer size on feed back. *

* It gradually increases the expected number of readable bytes if the previous * read fully filled the allocated buffer. It gradually decreases the expected * number of readable bytes if the read operation was not able to fill a certain * amount of the allocated buffer two times consecutively. Otherwise, it keeps * returning the same prediction. */ public class AdaptiveReceiveBufferSizePredictor implements ReceiveBufferSizePredictor { static final int DEFAULT_MINIMUM = 64; static final int DEFAULT_INITIAL = 1024; static final int DEFAULT_MAXIMUM = 65536; private static final int INDEX_INCREMENT = 4; private static final int INDEX_DECREMENT = 1; private static final int[] SIZE_TABLE; static { List sizeTable = new ArrayList(); for (int i = 1; i <= 8; i ++) { sizeTable.add(i); } for (int i = 4; i < 32; i ++) { long v = 1L << i; long inc = v >>> 4; v -= inc << 3; for (int j = 0; j < 8; j ++) { v += inc; if (v > Integer.MAX_VALUE) { sizeTable.add(Integer.MAX_VALUE); } else { sizeTable.add((int) v); } } } SIZE_TABLE = new int[sizeTable.size()]; for (int i = 0; i < SIZE_TABLE.length; i ++) { SIZE_TABLE[i] = sizeTable.get(i); } } private static int getSizeTableIndex(final int size) { if (size <= 16) { return size - 1; } int bits = 0; int v = size; do { v >>>= 1; bits ++; } while (v != 0); final int baseIdx = bits << 3; final int startIdx = baseIdx - 18; final int endIdx = baseIdx - 25; for (int i = startIdx; i >= endIdx; i --) { if (size >= SIZE_TABLE[i]) { return i; } } throw new Error("shouldn't reach here; please file a bug report."); } private final int minIndex; private final int maxIndex; private int index; private int nextReceiveBufferSize; private boolean decreaseNow; /** * Creates a new predictor with the default parameters. With the default * parameters, the expected buffer size starts from {@code 1024}, does not * go down below {@code 64}, and does not go up above {@code 65536}. */ public AdaptiveReceiveBufferSizePredictor() { this(DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM); } /** * Creates a new predictor with the specified parameters. * * @param minimum the inclusive lower bound of the expected buffer size * @param initial the initial buffer size when no feed back was received * @param maximum the inclusive upper bound of the expected buffer size */ public AdaptiveReceiveBufferSizePredictor(int minimum, int initial, int maximum) { if (minimum <= 0) { throw new IllegalArgumentException("minimum: " + minimum); } if (initial < minimum) { throw new IllegalArgumentException("initial: " + initial); } if (maximum < initial) { throw new IllegalArgumentException("maximum: " + maximum); } int minIndex = getSizeTableIndex(minimum); if (SIZE_TABLE[minIndex] < minimum) { this.minIndex = minIndex + 1; } else { this.minIndex = minIndex; } int maxIndex = getSizeTableIndex(maximum); if (SIZE_TABLE[maxIndex] > maximum) { this.maxIndex = maxIndex - 1; } else { this.maxIndex = maxIndex; } index = getSizeTableIndex(initial); nextReceiveBufferSize = SIZE_TABLE[index]; } public int nextReceiveBufferSize() { return nextReceiveBufferSize; } public void previousReceiveBufferSize(int previousReceiveBufferSize) { if (previousReceiveBufferSize <= SIZE_TABLE[Math.max(0, index - INDEX_DECREMENT - 1)]) { if (decreaseNow) { index = Math.max(index - INDEX_DECREMENT, minIndex); nextReceiveBufferSize = SIZE_TABLE[index]; decreaseNow = false; } else { decreaseNow = true; } } else if (previousReceiveBufferSize >= nextReceiveBufferSize) { index = Math.min(index + INDEX_INCREMENT, maxIndex); nextReceiveBufferSize = SIZE_TABLE[index]; decreaseNow = false; } } } AdaptiveReceiveBufferSizePredictorFactory.java000066400000000000000000000047301225554127700352300ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * The {@link ReceiveBufferSizePredictorFactory} that creates a new * {@link AdaptiveReceiveBufferSizePredictor}. */ public class AdaptiveReceiveBufferSizePredictorFactory implements ReceiveBufferSizePredictorFactory { private final int minimum; private final int initial; private final int maximum; /** * Creates a new factory with the default parameters. With the default * parameters, the expected buffer size starts from {@code 1024}, does not * go down below {@code 64}, and does not go up above {@code 65536}. */ public AdaptiveReceiveBufferSizePredictorFactory() { this(AdaptiveReceiveBufferSizePredictor.DEFAULT_MINIMUM, AdaptiveReceiveBufferSizePredictor.DEFAULT_INITIAL, AdaptiveReceiveBufferSizePredictor.DEFAULT_MAXIMUM); } /** * Creates a new factory with the specified parameters. * * @param minimum the inclusive lower bound of the expected buffer size * @param initial the initial buffer size when no feed back was received * @param maximum the inclusive upper bound of the expected buffer size */ public AdaptiveReceiveBufferSizePredictorFactory(int minimum, int initial, int maximum) { if (minimum <= 0) { throw new IllegalArgumentException("minimum: " + minimum); } if (initial < minimum) { throw new IllegalArgumentException("initial: " + initial); } if (maximum < initial) { throw new IllegalArgumentException("maximum: " + maximum); } this.minimum = minimum; this.initial = initial; this.maximum = maximum; } public ReceiveBufferSizePredictor getPredictor() throws Exception { return new AdaptiveReceiveBufferSizePredictor(minimum, initial, maximum); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/Channel.java000066400000000000000000000345161225554127700264330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.NotYetConnectedException; import java.nio.channels.SelectionKey; import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.ServerSocketChannel; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.channel.socket.nio.NioSocketChannelConfig; /** * A nexus to a network socket or a component which is capable of I/O * operations such as read, write, connect, and bind. *

* A channel provides a user: *

    *
  • the current state of the channel (e.g. is it open? is it connected?),
  • *
  • the {@linkplain ChannelConfig configuration parameters} of the channel (e.g. receive buffer size),
  • *
  • the I/O operations that the channel supports (e.g. read, write, connect, and bind), and
  • *
  • the {@link ChannelPipeline} which handles all {@linkplain ChannelEvent I/O events and requests} * associated with the channel.
  • *
* *

All I/O operations are asynchronous.

*

* All I/O operations in Netty are asynchronous. It means any I/O calls will * return immediately with no guarantee that the requested I/O operation has * been completed at the end of the call. Instead, you will be returned with * a {@link ChannelFuture} instance which will notify you when the requested I/O * operation has succeeded, failed, or canceled. * *

Channels are hierarchical

*

* A {@link Channel} can have a {@linkplain #getParent() parent} depending on * how it was created. For instance, a {@link SocketChannel}, that was accepted * by {@link ServerSocketChannel}, will return the {@link ServerSocketChannel} * as its parent on {@link #getParent()}. *

* The semantics of the hierarchical structure depends on the transport * implementation where the {@link Channel} belongs to. For example, you could * write a new {@link Channel} implementation that creates the sub-channels that * share one socket connection, as BEEP and * SSH do. * *

Downcast to access transport-specific operations

*

* Some transports exposes additional operations that is specific to the * transport. Down-cast the {@link Channel} to sub-type to invoke such * operations. For example, with the old I/O datagram transport, multicast * join / leave operations are provided by {@link DatagramChannel}. * *

InterestOps

*

* A {@link Channel} has a property called {@link #getInterestOps() interestOps} * which is similar to that of {@link SelectionKey#interestOps() NIO SelectionKey}. * It is represented as a bit * field which is composed of the two flags. *

    *
  • {@link #OP_READ} - If set, a message sent by a remote peer will be read * immediately. If unset, the message from the remote peer will not be read * until the {@link #OP_READ} flag is set again (i.e. read suspension).
  • *
  • {@link #OP_WRITE} - If set, a write request will not be sent to a remote * peer until the {@link #OP_WRITE} flag is cleared and the write request * will be pending in a queue. If unset, the write request will be flushed * out as soon as possible from the queue.
  • *
  • {@link #OP_READ_WRITE} - This is a combination of {@link #OP_READ} and * {@link #OP_WRITE}, which means only write requests are suspended.
  • *
  • {@link #OP_NONE} - This is a combination of (NOT {@link #OP_READ}) and * (NOT {@link #OP_WRITE}), which means only read operation is suspended.
  • *
*

* You can set or clear the {@link #OP_READ} flag to suspend and resume read * operation via {@link #setReadable(boolean)}. *

* Please note that you cannot suspend or resume write operation just like you * can set or clear {@link #OP_READ}. The {@link #OP_WRITE} flag is read only * and provided simply as a mean to tell you if the size of pending write * requests exceeded a certain threshold or not so that you don't issue too many * pending writes that lead to an {@link OutOfMemoryError}. For example, the * NIO socket transport uses the {@code writeBufferLowWaterMark} and * {@code writeBufferHighWaterMark} properties in {@link NioSocketChannelConfig} * to determine when to set or clear the {@link #OP_WRITE} flag. *

* * @apiviz.landmark * @apiviz.composedOf org.jboss.netty.channel.ChannelConfig * @apiviz.composedOf org.jboss.netty.channel.ChannelPipeline * * @apiviz.exclude ^org\.jboss\.netty\.channel\.([a-z]+\.)+[^\.]+Channel$ */ public interface Channel extends Comparable { /** * The {@link #getInterestOps() interestOps} value which tells that only * read operation has been suspended. */ int OP_NONE = 0; /** * The {@link #getInterestOps() interestOps} value which tells that neither * read nor write operation has been suspended. */ int OP_READ = 1; /** * The {@link #getInterestOps() interestOps} value which tells that both * read and write operation has been suspended. */ int OP_WRITE = 4; /** * The {@link #getInterestOps() interestOps} value which tells that only * write operation has been suspended. */ int OP_READ_WRITE = OP_READ | OP_WRITE; /** * Returns the unique integer ID of this channel. */ Integer getId(); /** * Returns the {@link ChannelFactory} which created this channel. */ ChannelFactory getFactory(); /** * Returns the parent of this channel. * * @return the parent channel. * {@code null} if this channel does not have a parent channel. */ Channel getParent(); /** * Returns the configuration of this channel. */ ChannelConfig getConfig(); /** * Returns the {@link ChannelPipeline} which handles {@link ChannelEvent}s * associated with this channel. */ ChannelPipeline getPipeline(); /** * Returns {@code true} if and only if this channel is open. */ boolean isOpen(); /** * Returns {@code true} if and only if this channel is bound to a * {@linkplain #getLocalAddress() local address}. */ boolean isBound(); /** * Returns {@code true} if and only if this channel is connected to a * {@linkplain #getRemoteAddress() remote address}. */ boolean isConnected(); /** * Returns the local address where this channel is bound to. The returned * {@link SocketAddress} is supposed to be down-cast into more concrete * type such as {@link InetSocketAddress} to retrieve the detailed * information. * * @return the local address of this channel. * {@code null} if this channel is not bound. */ SocketAddress getLocalAddress(); /** * Returns the remote address where this channel is connected to. The * returned {@link SocketAddress} is supposed to be down-cast into more * concrete type such as {@link InetSocketAddress} to retrieve the detailed * information. * * @return the remote address of this channel. * {@code null} if this channel is not connected. * If this channel is not connected but it can receive messages * from arbitrary remote addresses (e.g. {@link DatagramChannel}, * use {@link MessageEvent#getRemoteAddress()} to determine * the origination of the received message as this method will * return {@code null}. */ SocketAddress getRemoteAddress(); /** * Sends a message to this channel asynchronously. If this channel was * created by a connectionless transport (e.g. {@link DatagramChannel}) * and is not connected yet, you have to call {@link #write(Object, SocketAddress)} * instead. Otherwise, the write request will fail with * {@link NotYetConnectedException} and an {@code 'exceptionCaught'} event * will be triggered. * * @param message the message to write * * @return the {@link ChannelFuture} which will be notified when the * write request succeeds or fails * * @throws NullPointerException if the specified message is {@code null} */ ChannelFuture write(Object message); /** * Sends a message to this channel asynchronously. It has an additional * parameter that allows a user to specify where to send the specified * message instead of this channel's current remote address. If this * channel was created by a connectionless transport (e.g. {@link DatagramChannel}) * and is not connected yet, you must specify non-null address. Otherwise, * the write request will fail with {@link NotYetConnectedException} and * an {@code 'exceptionCaught'} event will be triggered. * * @param message the message to write * @param remoteAddress where to send the specified message. * This method is identical to {@link #write(Object)} * if {@code null} is specified here. * * @return the {@link ChannelFuture} which will be notified when the * write request succeeds or fails * * @throws NullPointerException if the specified message is {@code null} */ ChannelFuture write(Object message, SocketAddress remoteAddress); /** * Binds this channel to the specified local address asynchronously. * * @param localAddress where to bind * * @return the {@link ChannelFuture} which will be notified when the * bind request succeeds or fails * * @throws NullPointerException if the specified address is {@code null} */ ChannelFuture bind(SocketAddress localAddress); /** * Connects this channel to the specified remote address asynchronously. * * @param remoteAddress where to connect * * @return the {@link ChannelFuture} which will be notified when the * connection request succeeds or fails * * @throws NullPointerException if the specified address is {@code null} */ ChannelFuture connect(SocketAddress remoteAddress); /** * Disconnects this channel from the current remote address asynchronously. * * @return the {@link ChannelFuture} which will be notified when the * disconnection request succeeds or fails */ ChannelFuture disconnect(); /** * Unbinds this channel from the current local address asynchronously. * * @return the {@link ChannelFuture} which will be notified when the * unbind request succeeds or fails */ ChannelFuture unbind(); /** * Closes this channel asynchronously. If this channel is bound or * connected, it will be disconnected and unbound first. Once a channel * is closed, it can not be open again. Calling this method on a closed * channel has no effect. Please note that this method always returns the * same future instance. * * @return the {@link ChannelFuture} which will be notified when the * close request succeeds or fails */ ChannelFuture close(); /** * Returns the {@link ChannelFuture} which will be notified when this * channel is closed. This method always returns the same future instance. */ ChannelFuture getCloseFuture(); /** * Returns the current {@code interestOps} of this channel. * * @return {@link #OP_NONE}, {@link #OP_READ}, {@link #OP_WRITE}, or * {@link #OP_READ_WRITE} */ int getInterestOps(); /** * Returns {@code true} if and only if the I/O thread will read a message * from this channel. This method is a shortcut to the following code: *
     * return (getInterestOps() & OP_READ) != 0;
     * 
*/ boolean isReadable(); /** * Returns {@code true} if and only if the I/O thread will perform the * requested write operation immediately. Any write requests made when * this method returns {@code false} are queued until the I/O thread is * ready to process the queued write requests. This method is a shortcut * to the following code: *
     * return (getInterestOps() & OP_WRITE) == 0;
     * 
*/ boolean isWritable(); /** * Changes the {@code interestOps} of this channel asynchronously. * * @param interestOps the new {@code interestOps} * * @return the {@link ChannelFuture} which will be notified when the * {@code interestOps} change request succeeds or fails */ ChannelFuture setInterestOps(int interestOps); /** * Suspends or resumes the read operation of the I/O thread asynchronously. * This method is a shortcut to the following code: *
     * int interestOps = getInterestOps();
     * if (readable) {
     *     setInterestOps(interestOps | OP_READ);
     * } else {
     *     setInterestOps(interestOps & ~OP_READ);
     * }
     * 
* * @param readable {@code true} to resume the read operation and * {@code false} to suspend the read operation * * @return the {@link ChannelFuture} which will be notified when the * {@code interestOps} change request succeeds or fails */ ChannelFuture setReadable(boolean readable); /** * Retrieves an object which is {@link #setAttachment(Object) attached} to * this {@link Channel}. * * @return {@code null} if no object was attached or {@code null} was * attached */ Object getAttachment(); /** * Attaches an object to this {@link Channel} to store a stateful * information */ void setAttachment(Object attachment); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelConfig.java000066400000000000000000000125451225554127700275570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.nio.ByteOrder; import java.util.Map; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.HeapChannelBufferFactory; import org.jboss.netty.channel.socket.SocketChannelConfig; import org.jboss.netty.channel.socket.nio.NioSocketChannelConfig; /** * A set of configuration properties of a {@link Channel}. *

* Please down-cast to more specific configuration type such as * {@link SocketChannelConfig} or use {@link #setOptions(Map)} to set the * transport-specific properties: *

 * {@link Channel} ch = ...;
 * {@link SocketChannelConfig} cfg = ({@link SocketChannelConfig}) ch.getConfig();
 * cfg.setTcpNoDelay(false);
 * 
* *

Option map

* * An option map property is a dynamic write-only property which allows * the configuration of a {@link Channel} without down-casting its associated * {@link ChannelConfig}. To update an option map, please call {@link #setOptions(Map)}. *

* All {@link ChannelConfig} has the following options: * * * * * * * * * * * *
NameAssociated setter method
{@code "bufferFactory"}{@link #setBufferFactory(ChannelBufferFactory)}
{@code "connectTimeoutMillis"}{@link #setConnectTimeoutMillis(int)}
{@code "pipelineFactory"}{@link #setPipelineFactory(ChannelPipelineFactory)}
*

* More options are available in the sub-types of {@link ChannelConfig}. For * example, you can configure the parameters which are specific to a TCP/IP * socket as explained in {@link SocketChannelConfig} or {@link NioSocketChannelConfig}. * * @apiviz.has org.jboss.netty.channel.ChannelPipelineFactory * @apiviz.composedOf org.jboss.netty.channel.ReceiveBufferSizePredictor * * @apiviz.excludeSubtypes */ public interface ChannelConfig { /** * Sets the configuration properties from the specified {@link Map}. */ void setOptions(Map options); /** * Sets a configuration property with the specified name and value. * To override this method properly, you must call the super class: *

     * public boolean setOption(String name, Object value) {
     *     if (super.setOption(name, value)) {
     *         return true;
     *     }
     *
     *     if (name.equals("additionalOption")) {
     *         ....
     *         return true;
     *     }
     *
     *     return false;
     * }
     * 
* * @return {@code true} if and only if the property has been set */ boolean setOption(String name, Object value); /** * Returns the default {@link ChannelBufferFactory} used to create a new * {@link ChannelBuffer}. The default is {@link HeapChannelBufferFactory}. * You can specify a different factory to change the default * {@link ByteOrder} for example. */ ChannelBufferFactory getBufferFactory(); /** * Sets the default {@link ChannelBufferFactory} used to create a new * {@link ChannelBuffer}. The default is {@link HeapChannelBufferFactory}. * You can specify a different factory to change the default * {@link ByteOrder} for example. */ void setBufferFactory(ChannelBufferFactory bufferFactory); /** * Returns the {@link ChannelPipelineFactory} which will be used when * a child channel is created. If the {@link Channel} does not create * a child channel, this property is not used at all, and therefore will * be ignored. */ ChannelPipelineFactory getPipelineFactory(); /** * Sets the {@link ChannelPipelineFactory} which will be used when * a child channel is created. If the {@link Channel} does not create * a child channel, this property is not used at all, and therefore will * be ignored. */ void setPipelineFactory(ChannelPipelineFactory pipelineFactory); /** * Returns the connect timeout of the channel in milliseconds. If the * {@link Channel} does not support connect operation, this property is not * used at all, and therefore will be ignored. * * @return the connect timeout in milliseconds. {@code 0} if disabled. */ int getConnectTimeoutMillis(); /** * Sets the connect timeout of the channel in milliseconds. If the * {@link Channel} does not support connect operation, this property is not * used at all, and therefore will be ignored. * * @param connectTimeoutMillis the connect timeout in milliseconds. * {@code 0} to disable. */ void setConnectTimeoutMillis(int connectTimeoutMillis); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelDownstreamHandler.java000066400000000000000000000064321225554127700317710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * Handles or intercepts a downstream {@link ChannelEvent}, and sends a * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. *

* The most common use case of this interface is to intercept an I/O request * such as {@link Channel#write(Object)} and {@link Channel#close()}. * *

{@link SimpleChannelDownstreamHandler}

*

* In most cases, you will get to use a {@link SimpleChannelDownstreamHandler} * to implement a downstream handler because it provides an individual handler * method for each event type. You might want to implement this interface * directly though if you want to handle various types of events in more * generic way. * *

Firing an event to the next handler

*

* You can forward the received event downstream or upstream. In most cases, * {@link ChannelDownstreamHandler} will send the event downstream * (i.e. outbound) although it is legal to send the event upstream (i.e. inbound): * *

 * // Sending the event downstream (outbound)
 * void handleDownstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *     ...
 *     ctx.sendDownstream(e);
 *     ...
 * }
 *
 * // Sending the event upstream (inbound)
 * void handleDownstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *     ...
 *     ctx.sendUpstream(new {@link UpstreamChannelStateEvent}(...));
 *     ...
 * }
 * 
* *

Using the helper class to send an event

*

* You will also find various helper methods in {@link Channels} to be useful * to generate and send an artificial or manipulated event. *

* Caution: *

* Use the *Later(..) methods of the {@link Channels} class if you want to send an upstream event * from a {@link ChannelDownstreamHandler} otherwise you may run into threading issues. * *

State management

* * Please refer to {@link ChannelHandler}. * *

Thread safety

*

* {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} * may be invoked by more than one thread simultaneously. If the handler * accesses a shared resource or stores stateful information, you might need * proper synchronization in the handler implementation. * * @apiviz.exclude ^org\.jboss\.netty\.handler\..*$ */ public interface ChannelDownstreamHandler extends ChannelHandler { /** * Handles the specified downstream event. * * @param ctx the context object for this handler * @param e the downstream event to process or intercept */ void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelEvent.java000066400000000000000000000213661225554127700274340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.SocketAddress; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.socket.ServerSocketChannel; /** * An I/O event or I/O request associated with a {@link Channel}. *

* A {@link ChannelEvent} is handled by a series of {@link ChannelHandler}s in * a {@link ChannelPipeline}. * *

Upstream events and downstream events, and their interpretation

*

* Every event is either an upstream event or a downstream event. * If an event flows forward from the first handler to the last handler in a * {@link ChannelPipeline}, we call it an upstream event and say "an * event goes upstream." If an event flows backward from the last * handler to the first handler in a {@link ChannelPipeline}, we call it a * downstream event and say "an event goes downstream." * (Please refer to the diagram in {@link ChannelPipeline} for more explanation.) *

* When your server receives a message from a client, the event associated with * the received message is an upstream event. When your server sends a message * or reply to the client, the event associated with the write request is a * downstream event. The same rule applies for the client side. If your client * sent a request to the server, it means your client triggered a downstream * event. If your client received a response from the server, it means * your client will be notified with an upstream event. Upstream events are * often the result of inbound operations such as {@link InputStream#read(byte[])}, * and downstream events are the request for outbound operations such as * {@link OutputStream#write(byte[])}, {@link Socket#connect(SocketAddress)}, * and {@link Socket#close()}. * *

Upstream events

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Event nameEvent type and conditionMeaning
{@code "messageReceived"}{@link MessageEvent}a message object (e.g. {@link ChannelBuffer}) was received from a remote peer
{@code "exceptionCaught"}{@link ExceptionEvent}an exception was raised by an I/O thread or a {@link ChannelHandler}
{@code "channelOpen"}{@link ChannelStateEvent}
(state = {@link ChannelState#OPEN OPEN}, value = {@code true})
a {@link Channel} is open, but not bound nor connectedBe aware that this event is fired from within the Boss-Thread so you should not * execute any heavy operation in there as it will block the dispatching to other workers!
{@code "channelClosed"}{@link ChannelStateEvent}
(state = {@link ChannelState#OPEN OPEN}, value = {@code false})
a {@link Channel} was closed and all its related resources were released
{@code "channelBound"}{@link ChannelStateEvent}
(state = {@link ChannelState#BOUND BOUND}, value = {@link SocketAddress})
a {@link Channel} is open and bound to a local address, but not connected.Be aware that this event is fired from within the Boss-Thread so you should not * execute any heavy operation in there as it will block the dispatching to other workers!
{@code "channelUnbound"}{@link ChannelStateEvent}
(state = {@link ChannelState#BOUND BOUND}, value = {@code null})
a {@link Channel} was unbound from the current local address
{@code "channelConnected"}{@link ChannelStateEvent}
(state = {@link ChannelState#CONNECTED CONNECTED}, value = * {@link SocketAddress})
a {@link Channel} is open, bound to a local address, and connected to a remote addressBe aware that this event is fired from within the Boss-Thread so you should not * execute any heavy operation in there as it will block the dispatching to other workers!
{@code "writeComplete"}{@link WriteCompletionEvent}something has been written to a remote peer
{@code "channelDisconnected"}{@link ChannelStateEvent}
(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@code null})
a {@link Channel} was disconnected from its remote peer
{@code "channelInterestChanged"}{@link ChannelStateEvent}
(state = {@link ChannelState#INTEREST_OPS INTEREST_OPS}, no value)
a {@link Channel}'s {@link Channel#getInterestOps() interestOps} was changed
*

* These two additional event types are used only for a parent channel which * can have a child channel (e.g. {@link ServerSocketChannel}). *

* * * * * * * * * * * * * * *
Event nameEvent type and conditionMeaning
{@code "childChannelOpen"}{@link ChildChannelStateEvent}
({@code childChannel.isOpen() = true})
a child {@link Channel} was open (e.g. a server channel accepted a connection.)
{@code "childChannelClosed"}{@link ChildChannelStateEvent}
({@code childChannel.isOpen() = false})
a child {@link Channel} was closed (e.g. the accepted connection was closed.)
* *

Downstream events

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Event nameEvent type and conditionMeaning
{@code "write"}{@link MessageEvent}Send a message to the {@link Channel}.
{@code "bind"}{@link ChannelStateEvent}
(state = {@link ChannelState#BOUND BOUND}, value = {@link SocketAddress})
Bind the {@link Channel} to the specified local address.
{@code "unbind"}{@link ChannelStateEvent}
(state = {@link ChannelState#BOUND BOUND}, value = {@code null})
Unbind the {@link Channel} from the current local address.
{@code "connect"}{@link ChannelStateEvent}
(state = {@link ChannelState#CONNECTED CONNECTED}, value = * {@link SocketAddress})
Connect the {@link Channel} to the specified remote address.
{@code "disconnect"}{@link ChannelStateEvent}
(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@code null})
Disconnect the {@link Channel} from the current remote address.
{@code "close"}{@link ChannelStateEvent}
(state = {@link ChannelState#OPEN OPEN}, value = {@code false})
Close the {@link Channel}.
*

* Other event types and conditions which were not addressed here will be * ignored and discarded. Please note that there's no {@code "open"} in the * table. It is because a {@link Channel} is always open when it is created * by a {@link ChannelFactory}. * *

Additional resources worth reading

*

* Please refer to the {@link ChannelHandler} and {@link ChannelPipeline} * documentation to find out how an event flows in a pipeline and how to handle * the event in your application. * * @apiviz.landmark * @apiviz.composedOf org.jboss.netty.channel.ChannelFuture */ public interface ChannelEvent { /** * Returns the {@link Channel} which is associated with this event. */ Channel getChannel(); /** * Returns the {@link ChannelFuture} which is associated with this event. * If this event is an upstream event, this method will always return a * {@link SucceededChannelFuture} because the event has occurred already. * If this event is a downstream event (i.e. I/O request), the returned * future will be notified when the I/O request succeeds or fails. */ ChannelFuture getFuture(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelException.java000066400000000000000000000025561225554127700303110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link RuntimeException} which is thrown when an I/O operation fails. * * @apiviz.exclude */ public class ChannelException extends RuntimeException { private static final long serialVersionUID = 2908618315971075004L; /** * Creates a new exception. */ public ChannelException() { } /** * Creates a new exception. */ public ChannelException(String message, Throwable cause) { super(message, cause); } /** * Creates a new exception. */ public ChannelException(String message) { super(message); } /** * Creates a new exception. */ public ChannelException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelFactory.java000066400000000000000000000070051225554127700277540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.util.concurrent.Executor; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.util.ExternalResourceReleasable; /** * The main interface to a transport that creates a {@link Channel} associated * with a certain communication entity such as a network socket. For example, * the {@link NioServerSocketChannelFactory} creates a channel which has a * NIO-based server socket as its underlying communication entity. *

* Once a new {@link Channel} is created, the {@link ChannelPipeline} which * was specified as a parameter in the {@link #newChannel(ChannelPipeline)} * is attached to the new {@link Channel}, and starts to handle all associated * {@link ChannelEvent}s. * *

Graceful shutdown

*

* To shut down a network application service which is managed by a factory. * you should follow the following steps: *

    *
  1. close all channels created by the factory and their child channels * usually using {@link ChannelGroup#close()}, and
  2. *
  3. call {@link #releaseExternalResources()}.
  4. *
*

* For detailed transport-specific information on shutting down a factory, * please refer to the Javadoc of {@link ChannelFactory}'s subtypes, such as * {@link NioServerSocketChannelFactory}. * * @apiviz.landmark * @apiviz.has org.jboss.netty.channel.Channel oneway - - creates * * @apiviz.exclude ^org\.jboss\.netty\.channel\.([a-z]+\.)+.*ChannelFactory$ */ public interface ChannelFactory extends ExternalResourceReleasable { /** * Creates and opens a new {@link Channel} and attaches the specified * {@link ChannelPipeline} to the new {@link Channel}. * * @param pipeline the {@link ChannelPipeline} which is going to be * attached to the new {@link Channel} * * @return the newly open channel * * @throws ChannelException if failed to create and open a new channel */ Channel newChannel(ChannelPipeline pipeline); /** * Shudown the ChannelFactory and all the resource it created internal. */ void shutdown(); /** * Releases the external resources that this factory depends on to function. * An external resource is a resource that this factory didn't create by * itself. For example, {@link Executor}s that you specified in the factory * constructor are external resources. You can call this method to release * all external resources conveniently when the resources are not used by * this factory or any other part of your application. An unexpected * behavior will be resulted in if the resources are released when there's * an open channel which is managed by this factory. * * This will also call {@link #shutdown()} before do any action */ void releaseExternalResources(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelFuture.java000066400000000000000000000326231225554127700276230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.util.concurrent.TimeUnit; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.handler.execution.ExecutionHandler; /** * The result of an asynchronous {@link Channel} I/O operation. *

* All I/O operations in Netty are asynchronous. It means any I/O calls will * return immediately with no guarantee that the requested I/O operation has * been completed at the end of the call. Instead, you will be returned with * a {@link ChannelFuture} instance which gives you the information about the * result or status of the I/O operation. *

* A {@link ChannelFuture} is either uncompleted or completed. * When an I/O operation begins, a new future object is created. The new future * is uncompleted initially - it is neither succeeded, failed, nor cancelled * because the I/O operation is not finished yet. If the I/O operation is * finished either successfully, with failure, or by cancellation, the future is * marked as completed with more specific information, such as the cause of the * failure. Please note that even failure and cancellation belong to the * completed state. *

 *                                      +---------------------------+
 *                                      | Completed successfully    |
 *                                      +---------------------------+
 *                                 +---->      isDone() = true      |
 * +--------------------------+    |    |   isSuccess() = true      |
 * |        Uncompleted       |    |    +===========================+
 * +--------------------------+    |    | Completed with failure    |
 * |      isDone() = false    |    |    +---------------------------+
 * |   isSuccess() = false    |----+---->   isDone() = true         |
 * | isCancelled() = false    |    |    | getCause() = non-null     |
 * |    getCause() = null     |    |    +===========================+
 * +--------------------------+    |    | Completed by cancellation |
 *                                 |    +---------------------------+
 *                                 +---->      isDone() = true      |
 *                                      | isCancelled() = true      |
 *                                      +---------------------------+
 * 
* * Various methods are provided to let you check if the I/O operation has been * completed, wait for the completion, and retrieve the result of the I/O * operation. It also allows you to add {@link ChannelFutureListener}s so you * can get notified when the I/O operation is completed. * *

Prefer {@link #addListener(ChannelFutureListener)} to {@link #await()}

* * It is recommended to prefer {@link #addListener(ChannelFutureListener)} to * {@link #await()} wherever possible to get notified when an I/O operation is * done and to do any follow-up tasks. *

* {@link #addListener(ChannelFutureListener)} is non-blocking. It simply adds * the specified {@link ChannelFutureListener} to the {@link ChannelFuture}, and * I/O thread will notify the listeners when the I/O operation associated with * the future is done. {@link ChannelFutureListener} yields the best * performance and resource utilization because it does not block at all, but * it could be tricky to implement a sequential logic if you are not used to * event-driven programming. *

* By contrast, {@link #await()} is a blocking operation. Once called, the * caller thread blocks until the operation is done. It is easier to implement * a sequential logic with {@link #await()}, but the caller thread blocks * unnecessarily until the I/O operation is done and there's relatively * expensive cost of inter-thread notification. Moreover, there's a chance of * dead lock in a particular circumstance, which is described below. * *

Do not call {@link #await()} inside {@link ChannelHandler}

*

* The event handler methods in {@link ChannelHandler} is often called by * an I/O thread unless an {@link ExecutionHandler} is in the * {@link ChannelPipeline}. If {@link #await()} is called by an event handler * method, which is called by the I/O thread, the I/O operation it is waiting * for might never be complete because {@link #await()} can block the I/O * operation it is waiting for, which is a dead lock. *

 * // BAD - NEVER DO THIS
 * {@code @Override}
 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     if (e.getMessage() instanceof GoodByeMessage) {
 *         {@link ChannelFuture} future = e.getChannel().close();
 *         future.awaitUninterruptibly();
 *         // Perform post-closure operation
 *         // ...
 *     }
 * }
 *
 * // GOOD
 * {@code @Override}
 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     if (e.getMessage() instanceof GoodByeMessage) {
 *         {@link ChannelFuture} future = e.getChannel().close();
 *         future.addListener(new {@link ChannelFutureListener}() {
 *             public void operationComplete({@link ChannelFuture} future) {
 *                 // Perform post-closure operation
 *                 // ...
 *             }
 *         });
 *     }
 * }
 * 
*

* In spite of the disadvantages mentioned above, there are certainly the cases * where it is more convenient to call {@link #await()}. In such a case, please * make sure you do not call {@link #await()} in an I/O thread. Otherwise, * {@link IllegalStateException} will be raised to prevent a dead lock. * *

Do not confuse I/O timeout and await timeout

* * The timeout value you specify with {@link #await(long)}, * {@link #await(long, TimeUnit)}, {@link #awaitUninterruptibly(long)}, or * {@link #awaitUninterruptibly(long, TimeUnit)} are not related with I/O * timeout at all. If an I/O operation times out, the future will be marked as * 'completed with failure,' as depicted in the diagram above. For example, * connect timeout should be configured via a transport-specific option: *
 * // BAD - NEVER DO THIS
 * {@link ClientBootstrap} b = ...;
 * {@link ChannelFuture} f = b.connect(...);
 * f.awaitUninterruptibly(10, TimeUnit.SECONDS);
 * if (f.isCancelled()) {
 *     // Connection attempt cancelled by user
 * } else if (!f.isSuccess()) {
 *     // You might get a NullPointerException here because the future
 *     // might not be completed yet.
 *     f.getCause().printStackTrace();
 * } else {
 *     // Connection established successfully
 * }
 *
 * // GOOD
 * {@link ClientBootstrap} b = ...;
 * // Configure the connect timeout option.
 * b.setOption("connectTimeoutMillis", 10000);
 * {@link ChannelFuture} f = b.connect(...);
 * f.awaitUninterruptibly();
 *
 * // Now we are sure the future is completed.
 * assert f.isDone();
 *
 * if (f.isCancelled()) {
 *     // Connection attempt cancelled by user
 * } else if (!f.isSuccess()) {
 *     f.getCause().printStackTrace();
 * } else {
 *     // Connection established successfully
 * }
 * 
* * @apiviz.landmark * @apiviz.owns org.jboss.netty.channel.ChannelFutureListener - - notifies */ public interface ChannelFuture { /** * Returns a channel where the I/O operation associated with this * future takes place. */ Channel getChannel(); /** * Returns {@code true} if and only if this future is * complete, regardless of whether the operation was successful, failed, * or cancelled. */ boolean isDone(); /** * Returns {@code true} if and only if this future was * cancelled by a {@link #cancel()} method. */ boolean isCancelled(); /** * Returns {@code true} if and only if the I/O operation was completed * successfully. */ boolean isSuccess(); /** * Returns the cause of the failed I/O operation if the I/O operation has * failed. * * @return the cause of the failure. * {@code null} if succeeded or this future is not * completed yet. */ Throwable getCause(); /** * Cancels the I/O operation associated with this future * and notifies all listeners if canceled successfully. * * @return {@code true} if and only if the operation has been canceled. * {@code false} if the operation can't be canceled or is already * completed. */ boolean cancel(); /** * Marks this future as a success and notifies all * listeners. * * @return {@code true} if and only if successfully marked this future as * a success. Otherwise {@code false} because this future is * already marked as either a success or a failure. */ boolean setSuccess(); /** * Marks this future as a failure and notifies all * listeners. * * @return {@code true} if and only if successfully marked this future as * a failure. Otherwise {@code false} because this future is * already marked as either a success or a failure. */ boolean setFailure(Throwable cause); /** * Notifies the progress of the operation to the listeners that implements * {@link ChannelFutureProgressListener}. Please note that this method will * not do anything and return {@code false} if this future is complete * already. * * @return {@code true} if and only if notification was made. */ boolean setProgress(long amount, long current, long total); /** * Adds the specified listener to this future. The * specified listener is notified when this future is * {@linkplain #isDone() done}. If this future is already * completed, the specified listener is notified immediately. */ void addListener(ChannelFutureListener listener); /** * Removes the specified listener from this future. * The specified listener is no longer notified when this * future is {@linkplain #isDone() done}. If the specified * listener is not associated with this future, this method * does nothing and returns silently. */ void removeListener(ChannelFutureListener listener); /** * @deprecated Use {@link #sync()} or {@link #syncUninterruptibly()} instead. */ @Deprecated ChannelFuture rethrowIfFailed() throws Exception; /** * Waits for this future until it is done, and rethrows the cause of the failure if this future * failed. If the cause of the failure is a checked exception, it is wrapped with a new * {@link ChannelException} before being thrown. */ ChannelFuture sync() throws InterruptedException; /** * Waits for this future until it is done, and rethrows the cause of the failure if this future * failed. If the cause of the failure is a checked exception, it is wrapped with a new * {@link ChannelException} before being thrown. */ ChannelFuture syncUninterruptibly(); /** * Waits for this future to be completed. * * @throws InterruptedException * if the current thread was interrupted */ ChannelFuture await() throws InterruptedException; /** * Waits for this future to be completed without * interruption. This method catches an {@link InterruptedException} and * discards it silently. */ ChannelFuture awaitUninterruptibly(); /** * Waits for this future to be completed within the * specified time limit. * * @return {@code true} if and only if the future was completed within * the specified time limit * * @throws InterruptedException * if the current thread was interrupted */ boolean await(long timeout, TimeUnit unit) throws InterruptedException; /** * Waits for this future to be completed within the * specified time limit. * * @return {@code true} if and only if the future was completed within * the specified time limit * * @throws InterruptedException * if the current thread was interrupted */ boolean await(long timeoutMillis) throws InterruptedException; /** * Waits for this future to be completed within the * specified time limit without interruption. This method catches an * {@link InterruptedException} and discards it silently. * * @return {@code true} if and only if the future was completed within * the specified time limit */ boolean awaitUninterruptibly(long timeout, TimeUnit unit); /** * Waits for this future to be completed within the * specified time limit without interruption. This method catches an * {@link InterruptedException} and discards it silently. * * @return {@code true} if and only if the future was completed within * the specified time limit */ boolean awaitUninterruptibly(long timeoutMillis); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelFutureListener.java000066400000000000000000000047031225554127700313270ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.util.EventListener; /** * Listens to the result of a {@link ChannelFuture}. The result of the * asynchronous {@link Channel} I/O operation is notified once this listener * is added by calling {@link ChannelFuture#addListener(ChannelFutureListener)}. * *

Return the control to the caller quickly

* * {@link #operationComplete(ChannelFuture)} is directly called by an I/O * thread. Therefore, performing a time consuming task or a blocking operation * in the handler method can cause an unexpected pause during I/O. If you need * to perform a blocking operation on I/O completion, try to execute the * operation in a different thread using a thread pool. */ public interface ChannelFutureListener extends EventListener { /** * A {@link ChannelFutureListener} that closes the {@link Channel} which is * associated with the specified {@link ChannelFuture}. */ ChannelFutureListener CLOSE = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { future.getChannel().close(); } }; /** * A {@link ChannelFutureListener} that closes the {@link Channel} when the * operation ended up with a failure or cancellation rather than a success. */ ChannelFutureListener CLOSE_ON_FAILURE = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { if (!future.isSuccess()) { future.getChannel().close(); } } }; /** * Invoked when the I/O operation associated with the {@link ChannelFuture} * has been completed. * * @param future the source {@link ChannelFuture} which called this * callback */ void operationComplete(ChannelFuture future) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelFutureNotifier.java000066400000000000000000000023321225554127700313150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * ChannelFutureListener implementation which takes another ChannelFuture and notifies it * once the operationComplete method was called. */ public final class ChannelFutureNotifier implements ChannelFutureListener { private final ChannelFuture future; public ChannelFutureNotifier(ChannelFuture future) { this.future = future; } public void operationComplete(ChannelFuture cf) throws Exception { if (cf.isSuccess()) { future.setSuccess(); } else { future.setFailure(cf.getCause()); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelFutureProgressListener.java000066400000000000000000000043151225554127700330530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * Listens to the progress of a time-consuming I/O operation such as a large * file transfer. If this listener is added to a {@link ChannelFuture} of an * I/O operation that supports progress notification, the listener's * {@link #operationProgressed(ChannelFuture, long, long, long)} method will be * called back by an I/O thread. If the operation does not support progress * notification, {@link #operationProgressed(ChannelFuture, long, long, long)} * will not be invoked. Like a usual {@link ChannelFutureListener} that this * interface extends, {@link #operationComplete(ChannelFuture)} will be called * when the future is marked as complete. * *

Return the control to the caller quickly

* * {@link #operationProgressed(ChannelFuture, long, long, long)} and * {@link #operationComplete(ChannelFuture)} is directly called by an I/O * thread. Therefore, performing a time consuming task or a blocking operation * in the handler method can cause an unexpected pause during I/O. If you need * to perform a blocking operation on I/O completion, try to execute the * operation in a different thread using a thread pool. */ public interface ChannelFutureProgressListener extends ChannelFutureListener { /** * Invoked when the I/O operation associated with the {@link ChannelFuture} * has been progressed. * * @param future the source {@link ChannelFuture} which called this * callback */ void operationProgressed(ChannelFuture future, long amount, long current, long total) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelHandler.java000066400000000000000000000211701225554127700277210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.bootstrap.Bootstrap; import org.jboss.netty.channel.group.ChannelGroup; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Handles or intercepts a {@link ChannelEvent}, and sends a * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. * *

Sub-types

*

* {@link ChannelHandler} itself does not provide any method. To handle a * {@link ChannelEvent} you need to implement its sub-interfaces. There are * two sub-interfaces which handles a received event, one for upstream events * and the other for downstream events: *

    *
  • {@link ChannelUpstreamHandler} handles and intercepts an upstream {@link ChannelEvent}.
  • *
  • {@link ChannelDownstreamHandler} handles and intercepts a downstream {@link ChannelEvent}.
  • *
* * You will also find more detailed explanation from the documentation of * each sub-interface on how an event is interpreted when it goes upstream and * downstream respectively. * *

The context object

*

* A {@link ChannelHandler} is provided with a {@link ChannelHandlerContext} * object. A {@link ChannelHandler} is supposed to interact with the * {@link ChannelPipeline} it belongs to via a context object. Using the * context object, the {@link ChannelHandler} can pass events upstream or * downstream, modify the pipeline dynamically, or store the information * (attachment) which is specific to the handler. * *

State management

* * A {@link ChannelHandler} often needs to store some stateful information. * The simplest and recommended approach is to use member variables: *
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     private boolean loggedIn;
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         {@link Channel} ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             loggedIn = true;
 *         } else (o instanceof GetDataMessage) {
 *             if (loggedIn) {
 *                 ch.write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 * 
* Because the handler instance has a state variable which is dedicated to * one connection, you have to create a new handler instance for each new * channel to avoid a race condition where a unauthenticated client can get * the confidential information: *
 * // Create a new handler instance per channel.
 * // See {@link Bootstrap#setPipelineFactory(ChannelPipelineFactory)}.
 * public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(new DataServerHandler());
 *     }
 * }
 * 
* *

Using an attachment

* * Although it's recommended to use member variables to store the state of a * handler, for some reason you might not want to create many handler instances. * In such a case, you can use an attachment which is provided by * {@link ChannelHandlerContext}: *
 * {@code @Sharable}
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         {@link Channel} ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             ctx.setAttachment(true);
 *         } else (o instanceof GetDataMessage) {
 *             if (Boolean.TRUE.equals(ctx.getAttachment())) {
 *                 ch.write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 * 
* Now that the state of the handler is stored as an attachment, you can add the * same handler instance to different pipelines: *
 * public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private static final DataServerHandler SHARED = new DataServerHandler();
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(SHARED);
 *     }
 * }
 * 
* *

Using a {@link ChannelLocal}

* * If you have a state variable which needs to be accessed either from other * handlers or outside handlers, you can use {@link ChannelLocal}: *
 * public final class DataServerState {
 *
 *     public static final {@link ChannelLocal}<Boolean> loggedIn = new {@link ChannelLocal}<>() {
 *         protected Boolean initialValue(Channel channel) {
 *             return false;
 *         }
 *     }
 *     ...
 * }
 *
 * {@code @Sharable}
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         Channel ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             DataServerState.loggedIn.set(ch, true);
 *         } else (o instanceof GetDataMessage) {
 *             if (DataServerState.loggedIn.get(ch)) {
 *                 ctx.getChannel().write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 *
 * // Print the remote addresses of the authenticated clients:
 * {@link ChannelGroup} allClientChannels = ...;
 * for ({@link Channel} ch: allClientChannels) {
 *     if (DataServerState.loggedIn.get(ch)) {
 *         System.out.println(ch.getRemoteAddress());
 *     }
 * }
 * 
* *

The {@code @Sharable} annotation

*

* In the examples above which used an attachment or a {@link ChannelLocal}, * you might have noticed the {@code @Sharable} annotation. *

* If a {@link ChannelHandler} is annotated with the {@code @Sharable} * annotation, it means you can create an instance of the handler just once and * add it to one or more {@link ChannelPipeline}s multiple times without * a race condition. *

* If this annotation is not specified, you have to create a new handler * instance every time you add it to a pipeline because it has unshared state * such as member variables. *

* This annotation is provided for documentation purpose, just like * the JCIP annotations. * *

Additional resources worth reading

*

* Please refer to the {@link ChannelEvent} and {@link ChannelPipeline} to find * out what a upstream event and a downstream event are, what fundamental * differences they have, and how they flow in a pipeline. * * @apiviz.landmark * @apiviz.exclude ^org\.jboss\.netty\.handler\..*$ */ public interface ChannelHandler { /** * Indicates that the same instance of the annotated {@link ChannelHandler} * can be added to one or more {@link ChannelPipeline}s multiple times * without a race condition. *

* If this annotation is not specified, you have to create a new handler * instance every time you add it to a pipeline because it has unshared * state such as member variables. *

* This annotation is provided for documentation purpose, just like * the JCIP annotations. */ @Inherited @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Sharable { // no value } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelHandlerContext.java000066400000000000000000000156641225554127700313010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * Enables a {@link ChannelHandler} to interact with its {@link ChannelPipeline} * and other handlers. A handler can send a {@link ChannelEvent} upstream or * downstream, modify the {@link ChannelPipeline} it belongs to dynamically. * *

Sending an event

* * You can send or forward a {@link ChannelEvent} to the closest handler in the * same {@link ChannelPipeline} by calling {@link #sendUpstream(ChannelEvent)} * or {@link #sendDownstream(ChannelEvent)}. Please refer to * {@link ChannelPipeline} to understand how an event flows. * *

Modifying a pipeline

* * You can get the {@link ChannelPipeline} your handler belongs to by calling * {@link #getPipeline()}. A non-trivial application could insert, remove, or * replace handlers in the pipeline dynamically in runtime. * *

Retrieving for later use

* * You can keep the {@link ChannelHandlerContext} for later use, such as * triggering an event outside the handler methods, even from a different thread. *
 * public class MyHandler extends {@link SimpleChannelHandler}
 *                        implements {@link LifeCycleAwareChannelHandler} {
 *
 *     private {@link ChannelHandlerContext} ctx;
 *
 *     public void beforeAdd({@link ChannelHandlerContext} ctx) {
 *         this.ctx = ctx;
 *     }
 *
 *     public void login(String username, password) {
 *         {@link Channels}.write(
 *                 this.ctx,
 *                 {@link Channels}.succeededFuture(this.ctx.getChannel()),
 *                 new LoginMessage(username, password));
 *     }
 *     ...
 * }
 * 
* *

Storing stateful information

* * {@link #setAttachment(Object)} and {@link #getAttachment()} allow you to * store and access stateful information that is related with a handler and its * context. Please refer to {@link ChannelHandler} to learn various recommended * ways to manage stateful information. * *

A handler can have more than one context

* * Please note that a {@link ChannelHandler} instance can be added to more than * one {@link ChannelPipeline}. It means a single {@link ChannelHandler} * instance can have more than one {@link ChannelHandlerContext} and therefore * the single instance can be invoked with different * {@link ChannelHandlerContext}s if it is added to one or more * {@link ChannelPipeline}s more than once. *

* For example, the following handler will have as many independent attachments * as how many times it is added to pipelines, regardless if it is added to the * same pipeline multiple times or added to different pipelines multiple times: *

 * public class FactorialHandler extends {@link SimpleChannelHandler} {
 *
 *   // This handler will receive a sequence of increasing integers starting
 *   // from 1.
 *   {@code @Override}
 *   public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} evt) {
 *     Integer a = (Integer) ctx.getAttachment();
 *     Integer b = (Integer) evt.getMessage();
 *
 *     if (a == null) {
 *       a = 1;
 *     }
 *
 *     ctx.setAttachment(Integer.valueOf(a * b));
 *   }
 * }
 *
 * // Different context objects are given to "f1", "f2", "f3", and "f4" even if
 * // they refer to the same handler instance.  Because the FactorialHandler
 * // stores its state in a context object (as an attachment), the factorial is
 * // calculated correctly 4 times once the two pipelines (p1 and p2) are active.
 * FactorialHandler fh = new FactorialHandler();
 *
 * {@link ChannelPipeline} p1 = {@link Channels}.pipeline();
 * p1.addLast("f1", fh);
 * p1.addLast("f2", fh);
 *
 * {@link ChannelPipeline} p2 = {@link Channels}.pipeline();
 * p2.addLast("f3", fh);
 * p2.addLast("f4", fh);
 * 
* *

Additional resources worth reading

*

* Please refer to the {@link ChannelHandler}, {@link ChannelEvent}, and * {@link ChannelPipeline} to find out what a upstream event and a downstream * event are, what fundamental differences they have, how they flow in a * pipeline, and how to handle the event in your application. * * @apiviz.owns org.jboss.netty.channel.ChannelHandler */ public interface ChannelHandlerContext { /** * Returns the {@link Channel} that the {@link ChannelPipeline} belongs to. * This method is a shortcut to getPipeline().getChannel(). */ Channel getChannel(); /** * Returns the {@link ChannelPipeline} that the {@link ChannelHandler} * belongs to. */ ChannelPipeline getPipeline(); /** * Returns the name of the {@link ChannelHandler} in the * {@link ChannelPipeline}. */ String getName(); /** * Returns the {@link ChannelHandler} that this context object is * serving. */ ChannelHandler getHandler(); /** * Returns {@code true} if and only if the {@link ChannelHandler} is an * instance of {@link ChannelUpstreamHandler}. */ boolean canHandleUpstream(); /** * Returns {@code true} if and only if the {@link ChannelHandler} is an * instance of {@link ChannelDownstreamHandler}. */ boolean canHandleDownstream(); /** * Sends the specified {@link ChannelEvent} to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with this context. It is recommended to use * the shortcut methods in {@link Channels} rather than calling this method * directly. */ void sendUpstream(ChannelEvent e); /** * Sends the specified {@link ChannelEvent} to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with this context. It is * recommended to use the shortcut methods in {@link Channels} rather than * calling this method directly. */ void sendDownstream(ChannelEvent e); /** * Retrieves an object which is {@link #setAttachment(Object) attached} to * this context. * * @return {@code null} if no object was attached or * {@code null} was attached */ Object getAttachment(); /** * Attaches an object to this context to store a stateful information * specific to the {@link ChannelHandler} which is associated with this * context. */ void setAttachment(Object attachment); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelHandlerLifeCycleException.java000066400000000000000000000030071225554127700333570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link RuntimeException} which is thrown when a * {@link LifeCycleAwareChannelHandler} throws an {@link Exception} * in its handler methods. * * @apiviz.exclude */ public class ChannelHandlerLifeCycleException extends RuntimeException { private static final long serialVersionUID = 8764799996088850672L; /** * Creates a new exception. */ public ChannelHandlerLifeCycleException() { } /** * Creates a new exception. */ public ChannelHandlerLifeCycleException(String message, Throwable cause) { super(message, cause); } /** * Creates a new exception. */ public ChannelHandlerLifeCycleException(String message) { super(message); } /** * Creates a new exception. */ public ChannelHandlerLifeCycleException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelLocal.java000066400000000000000000000126261225554127700274040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap; import java.util.Collections; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; /** * A global variable that is local to a {@link Channel}. Think of this as a * variation of {@link ThreadLocal} whose key is a {@link Channel} rather than * a {@link Thread#currentThread()}. One difference is that you always have to * specify the {@link Channel} to access the variable. *

* Alternatively, you might want to use the * {@link ChannelHandlerContext#setAttachment(Object) ChannelHandlerContext.attachment} * property, which performs better. * @apiviz.stereotype utility */ public class ChannelLocal implements Iterable> { private final ConcurrentMap map = new ConcurrentIdentityWeakKeyHashMap(); private final ChannelFutureListener remover = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { remove(future.getChannel()); } }; private final boolean removeOnClose; /** * Creates a {@link Channel} local variable by calling {@link #ChannelLocal(boolean)} with * {@code false} as parameter */ public ChannelLocal() { this(false); } /** * Creates a {@link Channel} local variable. * * @param removeOnClose if {@code true} the {@link ChannelLocal} will remove a * {@link Channel} from it own once the {@link Channel} was closed. */ public ChannelLocal(boolean removeOnClose) { this.removeOnClose = removeOnClose; } /** * Returns the initial value of the variable. By default, it returns * {@code null}. Override it to change the initial value. * * @param channel the channel where this local variable is accessed with */ protected T initialValue(Channel channel) { return null; } /** * Returns the value of this variable. */ public T get(Channel channel) { if (channel == null) { throw new NullPointerException("channel"); } T value = map.get(channel); if (value == null) { value = initialValue(channel); if (value != null) { T oldValue = setIfAbsent(channel, value); if (oldValue != null) { value = oldValue; } } } return value; } /** * Sets the value of this variable. * * @return the old value. {@code null} if there was no old value. */ public T set(Channel channel, T value) { if (value == null) { return remove(channel); } else { if (channel == null) { throw new NullPointerException("channel"); } T old = map.put(channel, value); if (removeOnClose) { channel.getCloseFuture().addListener(remover); } return old; } } /** * Sets the value of this variable only when no value was set. * * @return {@code null} if the specified value was set. * An existing value if failed to set. */ public T setIfAbsent(Channel channel, T value) { if (value == null) { return get(channel); } else { if (channel == null) { throw new NullPointerException("channel"); } T mapping = map.putIfAbsent(channel, value); if (removeOnClose && mapping == null) { channel.getCloseFuture().addListener(remover); } return mapping; } } /** * Removes the variable and returns the removed value. If no value was set, * this method returns the return value of {@link #initialValue(Channel)}, * which is {@code null} by default. * * @return the removed value. * {@linkplain #initialValue(Channel) an initial value} (by default * {@code null}) if no value was set. */ public T remove(Channel channel) { if (channel == null) { throw new NullPointerException("channel"); } T removed = map.remove(channel); if (removed == null) { return initialValue(channel); } else { if (removeOnClose) { channel.getCloseFuture().removeListener(remover); } return removed; } } /** * Returns a read-only {@link Iterator} that holds all {@link Entry}'s of this ChannelLocal */ public Iterator> iterator() { return Collections.unmodifiableSet(map.entrySet()).iterator(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelPipeline.java000066400000000000000000000502251225554127700301140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.execution.ExecutionHandler; import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; import org.jboss.netty.handler.ssl.SslHandler; /** * A list of {@link ChannelHandler}s which handles or intercepts * {@link ChannelEvent}s of a {@link Channel}. {@link ChannelPipeline} * implements an advanced form of the * Intercepting * Filter pattern to give a user full control over how an event is handled * and how the {@link ChannelHandler}s in the pipeline interact with each other. * *

Creation of a pipeline

* * For each new channel, a new pipeline must be created and attached to the * channel. Once attached, the coupling between the channel and the pipeline * is permanent; the channel cannot attach another pipeline to it nor detach * the current pipeline from it. *

* The recommended way to create a new pipeline is to use the helper methods in * {@link Channels} rather than calling an individual implementation's * constructor: *

 * import static org.jboss.netty.channel.{@link Channels}.*;
 * {@link ChannelPipeline} pipeline = pipeline(); // same with Channels.pipeline()
 * 
* *

How an event flows in a pipeline

* * The following diagram describes how {@link ChannelEvent}s are processed by * {@link ChannelHandler}s in a {@link ChannelPipeline} typically. * A {@link ChannelEvent} can be handled by either a {@link ChannelUpstreamHandler} * or a {@link ChannelDownstreamHandler} and be forwarded to the closest * handler by calling {@link ChannelHandlerContext#sendUpstream(ChannelEvent)} * or {@link ChannelHandlerContext#sendDownstream(ChannelEvent)}. The meaning * of the event is interpreted somewhat differently depending on whether it is * going upstream or going downstream. Please refer to {@link ChannelEvent} for * more information. *
 *                                       I/O Request
 *                                     via {@link Channel} or
 *                                 {@link ChannelHandlerContext}
 *                                           |
 *  +----------------------------------------+---------------+
 *  |                  ChannelPipeline       |               |
 *  |                                       \|/              |
 *  |  +----------------------+  +-----------+------------+  |
 *  |  | Upstream Handler  N  |  | Downstream Handler  1  |  |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |            /|\                         |               |
 *  |             |                         \|/              |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |  | Upstream Handler N-1 |  | Downstream Handler  2  |  |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |            /|\                         .               |
 *  |             .                          .               |
 *  |     [ sendUpstream() ]        [ sendDownstream() ]     |
 *  |     [ + INBOUND data ]        [ + OUTBOUND data  ]     |
 *  |             .                          .               |
 *  |             .                         \|/              |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |  | Upstream Handler  2  |  | Downstream Handler M-1 |  |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |            /|\                         |               |
 *  |             |                         \|/              |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |  | Upstream Handler  1  |  | Downstream Handler  M  |  |
 *  |  +----------+-----------+  +-----------+------------+  |
 *  |            /|\                         |               |
 *  +-------------+--------------------------+---------------+
 *                |                         \|/
 *  +-------------+--------------------------+---------------+
 *  |             |                          |               |
 *  |     [ Socket.read() ]          [ Socket.write() ]      |
 *  |                                                        |
 *  |  Netty Internal I/O Threads (Transport Implementation) |
 *  +--------------------------------------------------------+
 * 
* An upstream event is handled by the upstream handlers in the bottom-up * direction as shown on the left side of the diagram. An upstream handler * usually handles the inbound data generated by the I/O thread on the bottom * of the diagram. The inbound data is often read from a remote peer via the * actual input operation such as {@link InputStream#read(byte[])}. * If an upstream event goes beyond the top upstream handler, it is discarded * silently. *

* A downstream event is handled by the downstream handler in the top-down * direction as shown on the right side of the diagram. A downstream handler * usually generates or transforms the outbound traffic such as write requests. * If a downstream event goes beyond the bottom downstream handler, it is * handled by an I/O thread associated with the {@link Channel}. The I/O thread * often performs the actual output operation such as {@link OutputStream#write(byte[])}. *

* For example, let us assume that we created the following pipeline: *

 * {@link ChannelPipeline} p = {@link Channels}.pipeline();
 * p.addLast("1", new UpstreamHandlerA());
 * p.addLast("2", new UpstreamHandlerB());
 * p.addLast("3", new DownstreamHandlerA());
 * p.addLast("4", new DownstreamHandlerB());
 * p.addLast("5", new UpstreamHandlerX());
 * 
* In the example above, the class whose name starts with {@code Upstream} means * it is an upstream handler. The class whose name starts with * {@code Downstream} means it is a downstream handler. *

* In the given example configuration, the handler evaluation order is 1, 2, 3, * 4, 5 when an event goes upstream. When an event goes downstream, the order * is 5, 4, 3, 2, 1. On top of this principle, {@link ChannelPipeline} skips * the evaluation of certain handlers to shorten the stack depth: *

    *
  • 3 and 4 don't implement {@link ChannelUpstreamHandler}, and therefore the * actual evaluation order of an upstream event will be: 1, 2, and 5.
  • *
  • 1, 2, and 5 don't implement {@link ChannelDownstreamHandler}, and * therefore the actual evaluation order of a downstream event will be: * 4 and 3.
  • *
  • If 5 extended {@link SimpleChannelHandler} which implements both * {@link ChannelUpstreamHandler} and {@link ChannelDownstreamHandler}, the * evaluation order of an upstream and a downstream event could be 125 and * 543 respectively.
  • *
* *

Building a pipeline

*

* A user is supposed to have one or more {@link ChannelHandler}s in a * pipeline to receive I/O events (e.g. read) and to request I/O operations * (e.g. write and close). For example, a typical server will have the following * handlers in each channel's pipeline, but your mileage may vary depending on * the complexity and characteristics of the protocol and business logic: * *

    *
  1. Protocol Decoder - translates binary data (e.g. {@link ChannelBuffer}) * into a Java object.
  2. *
  3. Protocol Encoder - translates a Java object into binary data.
  4. *
  5. {@link ExecutionHandler} - applies a thread model.
  6. *
  7. Business Logic Handler - performs the actual business logic * (e.g. database access).
  8. *
* * and it could be represented as shown in the following example: * *
 * {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()};
 * pipeline.addLast("decoder", new MyProtocolDecoder());
 * pipeline.addLast("encoder", new MyProtocolEncoder());
 * pipeline.addLast("executor", new {@link ExecutionHandler}(
 *         new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576)));
 * pipeline.addLast("handler", new MyBusinessLogicHandler());
 * 
* *

Thread safety

*

* A {@link ChannelHandler} can be added or removed at any time because a * {@link ChannelPipeline} is thread safe. For example, you can insert a * {@link SslHandler} when sensitive information is about to be exchanged, * and remove it after the exchange. * *

Pitfall

*

* Due to the internal implementation detail of the current default * {@link ChannelPipeline}, the following code does not work as expected if * FirstHandler is the last handler in the pipeline: *

 * public class FirstHandler extends {@link SimpleChannelUpstreamHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         // Remove this handler from the pipeline,
 *         ctx.getPipeline().remove(this);
 *         // And let SecondHandler handle the current event.
 *         ctx.getPipeline().addLast("2nd", new SecondHandler());
 *         ctx.sendUpstream(e);
 *     }
 * }
 * 
* To implement the expected behavior, you have to add SecondHandler * before the removal or make sure there is at least one more handler between * FirstHandler and SecondHandler. * * @apiviz.landmark * @apiviz.composedOf org.jboss.netty.channel.ChannelHandlerContext * @apiviz.owns org.jboss.netty.channel.ChannelHandler * @apiviz.uses org.jboss.netty.channel.ChannelSink - - sends events downstream */ public interface ChannelPipeline { /** * Inserts a {@link ChannelHandler} at the first position of this pipeline. * * @param name the name of the handler to insert first * @param handler the handler to insert first * * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified name or handler is {@code null} */ void addFirst(String name, ChannelHandler handler); /** * Appends a {@link ChannelHandler} at the last position of this pipeline. * * @param name the name of the handler to append * @param handler the handler to append * * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified name or handler is {@code null} */ void addLast(String name, ChannelHandler handler); /** * Inserts a {@link ChannelHandler} before an existing handler of this * pipeline. * * @param baseName the name of the existing handler * @param name the name of the handler to insert before * @param handler the handler to insert before * * @throws NoSuchElementException * if there's no such entry with the specified {@code baseName} * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified baseName, name, or handler is {@code null} */ void addBefore(String baseName, String name, ChannelHandler handler); /** * Inserts a {@link ChannelHandler} after an existing handler of this * pipeline. * * @param baseName the name of the existing handler * @param name the name of the handler to insert after * @param handler the handler to insert after * * @throws NoSuchElementException * if there's no such entry with the specified {@code baseName} * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified baseName, name, or handler is {@code null} */ void addAfter(String baseName, String name, ChannelHandler handler); /** * Removes the specified {@link ChannelHandler} from this pipeline. * * @throws NoSuchElementException * if there's no such handler in this pipeline * @throws NullPointerException * if the specified handler is {@code null} */ void remove(ChannelHandler handler); /** * Removes the {@link ChannelHandler} with the specified name from this * pipeline. * * @return the removed handler * * @throws NoSuchElementException * if there's no such handler with the specified name in this pipeline * @throws NullPointerException * if the specified name is {@code null} */ ChannelHandler remove(String name); /** * Removes the {@link ChannelHandler} of the specified type from this * pipeline * * @param the type of the handler * @param handlerType the type of the handler * * @return the removed handler * * @throws NoSuchElementException * if there's no such handler of the specified type in this pipeline * @throws NullPointerException * if the specified handler type is {@code null} */ T remove(Class handlerType); /** * Removes the first {@link ChannelHandler} in this pipeline. * * @return the removed handler * * @throws NoSuchElementException * if this pipeline is empty */ ChannelHandler removeFirst(); /** * Removes the last {@link ChannelHandler} in this pipeline. * * @return the removed handler * * @throws NoSuchElementException * if this pipeline is empty */ ChannelHandler removeLast(); /** * Replaces the specified {@link ChannelHandler} with a new handler in * this pipeline. * * @throws NoSuchElementException * if the specified old handler does not exist in this pipeline * @throws IllegalArgumentException * if a handler with the specified new name already exists in this * pipeline, except for the handler to be replaced * @throws NullPointerException * if the specified old handler, new name, or new handler is * {@code null} */ void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler); /** * Replaces the {@link ChannelHandler} of the specified name with a new * handler in this pipeline. * * @return the removed handler * * @throws NoSuchElementException * if the handler with the specified old name does not exist in this pipeline * @throws IllegalArgumentException * if a handler with the specified new name already exists in this * pipeline, except for the handler to be replaced * @throws NullPointerException * if the specified old handler, new name, or new handler is * {@code null} */ ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler); /** * Replaces the {@link ChannelHandler} of the specified type with a new * handler in this pipeline. * * @return the removed handler * * @throws NoSuchElementException * if the handler of the specified old handler type does not exist * in this pipeline * @throws IllegalArgumentException * if a handler with the specified new name already exists in this * pipeline, except for the handler to be replaced * @throws NullPointerException * if the specified old handler, new name, or new handler is * {@code null} */ T replace(Class oldHandlerType, String newName, ChannelHandler newHandler); /** * Returns the first {@link ChannelHandler} in this pipeline. * * @return the first handler. {@code null} if this pipeline is empty. */ ChannelHandler getFirst(); /** * Returns the last {@link ChannelHandler} in this pipeline. * * @return the last handler. {@code null} if this pipeline is empty. */ ChannelHandler getLast(); /** * Returns the {@link ChannelHandler} with the specified name in this * pipeline. * * @return the handler with the specified name. * {@code null} if there's no such handler in this pipeline. */ ChannelHandler get(String name); /** * Returns the {@link ChannelHandler} of the specified type in this * pipeline. * * @return the handler of the specified handler type. * {@code null} if there's no such handler in this pipeline. */ T get(Class handlerType); /** * Returns the context object of the specified {@link ChannelHandler} in * this pipeline. * * @return the context object of the specified handler. * {@code null} if there's no such handler in this pipeline. */ ChannelHandlerContext getContext(ChannelHandler handler); /** * Returns the context object of the {@link ChannelHandler} with the * specified name in this pipeline. * * @return the context object of the handler with the specified name. * {@code null} if there's no such handler in this pipeline. */ ChannelHandlerContext getContext(String name); /** * Returns the context object of the {@link ChannelHandler} of the * specified type in this pipeline. * * @return the context object of the handler of the specified type. * {@code null} if there's no such handler in this pipeline. */ ChannelHandlerContext getContext(Class handlerType); /** * Sends the specified {@link ChannelEvent} to the first * {@link ChannelUpstreamHandler} in this pipeline. * * @throws NullPointerException * if the specified event is {@code null} */ void sendUpstream(ChannelEvent e); /** * Sends the specified {@link ChannelEvent} to the last * {@link ChannelDownstreamHandler} in this pipeline. * * @throws NullPointerException * if the specified event is {@code null} */ void sendDownstream(ChannelEvent e); /** * Schedules the specified task to be executed in the I/O thread associated * with this pipeline's {@link Channel}. */ ChannelFuture execute(Runnable task); /** * Returns the {@link Channel} that this pipeline is attached to. * * @return the channel. {@code null} if this pipeline is not attached yet. */ Channel getChannel(); /** * Returns the {@link ChannelSink} that this pipeline is attached to. * * @return the sink. {@code null} if this pipeline is not attached yet. */ ChannelSink getSink(); /** * Attaches this pipeline to the specified {@link Channel} and * {@link ChannelSink}. Once a pipeline is attached, it can't be detached * nor attached again. * * @throws IllegalStateException if this pipeline is attached already */ void attach(Channel channel, ChannelSink sink); /** * Returns {@code true} if and only if this pipeline is attached to * a {@link Channel}. */ boolean isAttached(); /** * Returns the {@link List} of the handler names. */ List getNames(); /** * Converts this pipeline into an ordered {@link Map} whose keys are * handler names and whose values are handlers. */ Map toMap(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelPipelineCoverage.java000066400000000000000000000025631225554127700315720ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.jboss.netty.channel.ChannelHandler.Sharable; /** * @deprecated Use the {@link Sharable} annotation instead. * @apiviz.exclude */ @Inherited @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Deprecated public @interface ChannelPipelineCoverage { /** * {@code "all"} */ String ALL = "all"; /** * {@code "one"} */ String ONE = "one"; /** * The value of this annotation */ String value(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelPipelineException.java000066400000000000000000000030341225554127700317670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelException} which is thrown when a {@link ChannelPipeline} * failed to process a {@link ChannelEvent} or when a {@link ChannelPipelineFactory} * failed to initialize a {@link ChannelPipeline}. * * @apiviz.exclude */ public class ChannelPipelineException extends ChannelException { private static final long serialVersionUID = 3379174210419885980L; /** * Creates a new instance. */ public ChannelPipelineException() { } /** * Creates a new instance. */ public ChannelPipelineException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public ChannelPipelineException(String message) { super(message); } /** * Creates a new instance. */ public ChannelPipelineException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelPipelineFactory.java000066400000000000000000000034001225554127700314350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.bootstrap.Bootstrap; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; /** * Creates a new {@link ChannelPipeline} for a new {@link Channel}. *

* When a {@linkplain ServerChannel server-side channel} accepts a new incoming * connection, a new child channel is created for each newly accepted connection. * A new child channel uses a new {@link ChannelPipeline}, which is created by * the {@link ChannelPipelineFactory} specified in the server-side channel's * {@link ChannelConfig#getPipelineFactory() "pipelineFactory"} option. *

* Also, when a {@link ClientBootstrap} or {@link ConnectionlessBootstrap} * creates a new channel, it uses the {@link Bootstrap#getPipelineFactory() "pipelineFactory"} * property to create a new {@link ChannelPipeline} for each new channel. * * @apiviz.has org.jboss.netty.channel.ChannelPipeline oneway - - creates */ public interface ChannelPipelineFactory { /** * Returns a newly created {@link ChannelPipeline}. */ ChannelPipeline getPipeline() throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelSink.java000066400000000000000000000034021225554127700272460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * Receives and processes the terminal downstream {@link ChannelEvent}s. *

* A {@link ChannelSink} is an internal component which is supposed to be * implemented by a transport provider. Most users will not see this type * in their code. * * @apiviz.uses org.jboss.netty.channel.ChannelPipeline - - sends events upstream */ public interface ChannelSink { /** * Invoked by {@link ChannelPipeline} when a downstream {@link ChannelEvent} * has reached its terminal (the head of the pipeline). */ void eventSunk(ChannelPipeline pipeline, ChannelEvent e) throws Exception; /** * Invoked by {@link ChannelPipeline} when an exception was raised while * one of its {@link ChannelHandler}s process a {@link ChannelEvent}. */ void exceptionCaught(ChannelPipeline pipeline, ChannelEvent e, ChannelPipelineException cause) throws Exception; /** * Execute the given {@link Runnable} later in the io-thread. * Some implementation may not support this and just execute it directly. */ ChannelFuture execute(ChannelPipeline pipeline, Runnable task); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelState.java000066400000000000000000000071171225554127700274310ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; /** * The current or future state of a {@link Channel}. *

* The state of a {@link Channel} is interpreted differently depending on the * {@linkplain ChannelStateEvent#getValue() value} of a {@link ChannelStateEvent} * and the direction of the event in a {@link ChannelPipeline}: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
DirectionStateValueMeaning
Upstream{@link #OPEN}{@code true}The channel is open.
Upstream{@link #OPEN}{@code false}The channel is closed.
Upstream{@link #BOUND}{@link SocketAddress}The channel is bound to a local address.
Upstream{@link #BOUND}{@code null}The channel is unbound to a local address.
Upstream{@link #CONNECTED}{@link SocketAddress}The channel is connected to a remote address.
Upstream{@link #CONNECTED}{@code null}The channel is disconnected from a remote address.
Upstream{@link #INTEREST_OPS}an integerThe channel interestOps has been changed.
Downstream{@link #OPEN}{@code true}N/A
Downstream{@link #OPEN}{@code false}Close the channel.
Downstream{@link #BOUND}{@link SocketAddress}Bind the channel to the specified local address.
Downstream{@link #BOUND}{@code null}Unbind the channel from the current local address.
Downstream{@link #CONNECTED}{@link SocketAddress}Connect the channel to the specified remote address.
Downstream{@link #CONNECTED}{@code null}Disconnect the channel from the current remote address.
Downstream{@link #INTEREST_OPS}an integerChange the interestOps of the channel.
*

* To see how an event is interpreted further, please refer to {@link ChannelEvent}. */ public enum ChannelState { /** * Represents a {@link Channel}'s {@link Channel#isOpen() open} property */ OPEN, /** * Represents a {@link Channel}'s {@link Channel#isBound() bound} property */ BOUND, /** * Represents a {@link Channel}'s {@link Channel#isConnected() connected} * property */ CONNECTED, /** * Represents a {@link Channel}'s {@link Channel#getInterestOps() interestOps} * property */ INTEREST_OPS } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelStateEvent.java000066400000000000000000000030041225554127700304220ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelEvent} which represents the change of the {@link Channel} * state. It can mean the notification of a change or the request for a * change, depending on whether it is an upstream event or a downstream event * respectively. Please refer to the {@link ChannelEvent} documentation to * find out what an upstream event and a downstream event are and what * fundamental differences they have. * * @apiviz.has org.jboss.netty.channel.ChannelState */ public interface ChannelStateEvent extends ChannelEvent { /** * Returns the changed property of the {@link Channel}. */ ChannelState getState(); /** * Returns the value of the changed property of the {@link Channel}. * Please refer to {@link ChannelState} documentation to find out the * allowed values for each property. */ Object getValue(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChannelUpstreamHandler.java000066400000000000000000000073041225554127700314450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.util.concurrent.Executor; import org.jboss.netty.handler.execution.ExecutionHandler; /** * Handles or intercepts an upstream {@link ChannelEvent}, and sends a * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. *

* The most common use case of this interface is to intercept an I/O event * generated by I/O workers to transform the received messages or execute * the relevant business logic. * *

{@link SimpleChannelUpstreamHandler}

*

* In most cases, you will get to use a {@link SimpleChannelUpstreamHandler} to * implement an upstream handler because it provides an individual handler * method for each event type. You might want to implement this interface * directly though if you want to handle various types of events in more * generic way. * *

Firing an event to the next handler

*

* You can forward the received event upstream or downstream. In most cases, * {@link ChannelUpstreamHandler} will send the event upstream (i.e. inbound) * although it is legal to send the event downstream (i.e. outbound): * *

 * // Sending the event upstream (inbound)
 * void handleUpstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *     ...
 *     ctx.sendUpstream(e);
 *     ...
 * }
 *
 * // Sending the event downstream (outbound)
 * void handleDownstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *     ...
 *     ctx.sendDownstream(new {@link DownstreamMessageEvent}(...));
 *     ...
 * }
 * 
* *

Using the helper class to send an event

*

* You will also find various helper methods in {@link Channels} to be useful * to generate and send an artificial or manipulated event. * *

State management

* * Please refer to {@link ChannelHandler}. * *

Thread safety

*

* {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} * will be invoked sequentially by the same thread (i.e. an I/O thread) and * therefore a handler does not need to worry about being invoked with a new * upstream event before the previous upstream event is finished. *

* This does not necessarily mean that there's a dedicated thread per * {@link Channel}; the I/O thread of some transport can serve more than one * {@link Channel} (e.g. NIO transport), while the I/O thread of other * transports can serve only one (e.g. OIO transport). *

* However, if you add an {@link ExecutionHandler} to a {@link ChannelPipeline}, * this behavior changes depending on what {@link Executor} was employed to * dispatch the events. Please refer to {@link ExecutionHandler} for more * information. * * @apiviz.exclude ^org\.jboss\.netty\.handler\..*$ */ public interface ChannelUpstreamHandler extends ChannelHandler { /** * Handles the specified upstream event. * * @param ctx the context object for this handler * @param e the upstream event to process or intercept */ void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/Channels.java000066400000000000000000000766571225554127700266320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; import java.util.Map; import org.jboss.netty.util.internal.ConversionUtil; /** * A helper class which provides various convenience methods related with * {@link Channel}, {@link ChannelHandler}, and {@link ChannelPipeline}. * *

Factory methods

*

* It is always recommended to use the factory methods provided by * {@link Channels} rather than calling the constructor of the implementation * types. *

    *
  • {@link #pipeline()}
  • *
  • {@link #pipeline(ChannelPipeline)}
  • *
  • {@link #pipelineFactory(ChannelPipeline)}
  • *
  • {@link #succeededFuture(Channel)}
  • *
  • {@link #failedFuture(Channel, Throwable)}
  • *
* *

Upstream and downstream event generation

*

* Various event generation methods are provided to simplify the generation of * upstream events and downstream events. It is always recommended to use the * event generation methods provided by {@link Channels} rather than calling * {@link ChannelHandlerContext#sendUpstream(ChannelEvent)} or * {@link ChannelHandlerContext#sendDownstream(ChannelEvent)} by yourself. * @apiviz.landmark */ public final class Channels { // pipeline factory methods /** * Creates a new {@link ChannelPipeline}. */ public static ChannelPipeline pipeline() { return new DefaultChannelPipeline(); } /** * Creates a new {@link ChannelPipeline} which contains the specified * {@link ChannelHandler}s. The names of the specified handlers are * generated automatically; the first handler's name is {@code "0"}, * the second handler's name is {@code "1"}, the third handler's name is * {@code "2"}, and so on. */ public static ChannelPipeline pipeline(ChannelHandler... handlers) { if (handlers == null) { throw new NullPointerException("handlers"); } ChannelPipeline newPipeline = pipeline(); for (int i = 0; i < handlers.length; i ++) { ChannelHandler h = handlers[i]; if (h == null) { break; } newPipeline.addLast(ConversionUtil.toString(i), h); } return newPipeline; } /** * Creates a new {@link ChannelPipeline} which contains the same entries * with the specified {@code pipeline}. Please note that only the names * and the references of the {@link ChannelHandler}s will be copied; a new * {@link ChannelHandler} instance will never be created. */ public static ChannelPipeline pipeline(ChannelPipeline pipeline) { ChannelPipeline newPipeline = pipeline(); for (Map.Entry e: pipeline.toMap().entrySet()) { newPipeline.addLast(e.getKey(), e.getValue()); } return newPipeline; } /** * Creates a new {@link ChannelPipelineFactory} which creates a new * {@link ChannelPipeline} which contains the same entries with the * specified {@code pipeline}. Please note that only the names and the * references of the {@link ChannelHandler}s will be copied; a new * {@link ChannelHandler} instance will never be created. */ public static ChannelPipelineFactory pipelineFactory( final ChannelPipeline pipeline) { return new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { return pipeline(pipeline); } }; } // future factory methods /** * Creates a new non-cancellable {@link ChannelFuture} for the specified * {@link Channel}. */ public static ChannelFuture future(Channel channel) { return future(channel, false); } /** * Creates a new {@link ChannelFuture} for the specified {@link Channel}. * * @param cancellable {@code true} if and only if the returned future * can be canceled by {@link ChannelFuture#cancel()} */ public static ChannelFuture future(Channel channel, boolean cancellable) { return new DefaultChannelFuture(channel, cancellable); } /** * Creates a new {@link ChannelFuture} which is already succeeded for the * specified {@link Channel}. */ public static ChannelFuture succeededFuture(Channel channel) { if (channel instanceof AbstractChannel) { return ((AbstractChannel) channel).getSucceededFuture(); } else { return new SucceededChannelFuture(channel); } } /** * Creates a new {@link ChannelFuture} which has failed already for the * specified {@link Channel}. * * @param cause the cause of the failure */ public static ChannelFuture failedFuture(Channel channel, Throwable cause) { return new FailedChannelFuture(channel, cause); } // event emission methods /** * Sends a {@code "channelOpen"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. If the specified channel has a parent, * a {@code "childChannelOpen"} event will be sent, too. */ public static void fireChannelOpen(Channel channel) { // Notify the parent handler. if (channel.getParent() != null) { fireChildChannelStateChanged(channel.getParent(), channel); } channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.OPEN, Boolean.TRUE)); } /** * Sends a {@code "channelOpen"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. *

* Please note that this method does not trigger a * {@code "childChannelOpen"} event unlike {@link #fireChannelOpen(Channel)} * method. */ public static void fireChannelOpen(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.OPEN, Boolean.TRUE)); } /** * Sends a {@code "channelBound"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param localAddress * the local address where the specified channel is bound */ public static void fireChannelBound(Channel channel, SocketAddress localAddress) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.BOUND, localAddress)); } /** * Sends a {@code "channelBound"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param localAddress * the local address where the specified channel is bound */ public static void fireChannelBound(ChannelHandlerContext ctx, SocketAddress localAddress) { ctx.sendUpstream(new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.BOUND, localAddress)); } /** * Sends a {@code "channelConnected"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param remoteAddress * the remote address where the specified channel is connected */ public static void fireChannelConnected(Channel channel, SocketAddress remoteAddress) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.CONNECTED, remoteAddress)); } /** * Sends a {@code "channelConnected"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param remoteAddress * the remote address where the specified channel is connected */ public static void fireChannelConnected(ChannelHandlerContext ctx, SocketAddress remoteAddress) { ctx.sendUpstream(new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.CONNECTED, remoteAddress)); } /** * Sends a {@code "messageReceived"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param message the received message */ public static void fireMessageReceived(Channel channel, Object message) { fireMessageReceived(channel, message, null); } /** * Sends a {@code "messageReceived"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} belongs. * * @param message the received message * @param remoteAddress the remote address where the received message * came from */ public static void fireMessageReceived(Channel channel, Object message, SocketAddress remoteAddress) { channel.getPipeline().sendUpstream( new UpstreamMessageEvent(channel, message, remoteAddress)); } /** * Sends a {@code "messageReceived"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param message the received message */ public static void fireMessageReceived(ChannelHandlerContext ctx, Object message) { ctx.sendUpstream(new UpstreamMessageEvent(ctx.getChannel(), message, null)); } /** * Sends a {@code "messageReceived"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param message the received message * @param remoteAddress the remote address where the received message * came from */ public static void fireMessageReceived( ChannelHandlerContext ctx, Object message, SocketAddress remoteAddress) { ctx.sendUpstream(new UpstreamMessageEvent( ctx.getChannel(), message, remoteAddress)); } /** * Sends a {@code "writeComplete"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} in the next io-thread. */ public static ChannelFuture fireWriteCompleteLater(final Channel channel, final long amount) { return channel.getPipeline().execute(new Runnable() { public void run() { fireWriteComplete(channel, amount); } }); } /** * Sends a {@code "writeComplete"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. */ public static void fireWriteComplete(Channel channel, long amount) { if (amount == 0) { return; } channel.getPipeline().sendUpstream( new DefaultWriteCompletionEvent(channel, amount)); } /** * Sends a {@code "writeComplete"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) { ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount)); } /** * Sends a {@code "channelInterestChanged"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelInterestChangedLater(final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelInterestChanged(channel); } }); } /** * Sends a {@code "channelInterestChanged"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. */ public static void fireChannelInterestChanged(Channel channel) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.INTEREST_OPS, Channel.OP_READ)); } /** * Sends a {@code "channelInterestChanged"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelInterestChanged( ChannelHandlerContext ctx) { ctx.sendUpstream( new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ)); } /** * Sends a {@code "channelDisconnected"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelDisconnectedLater(final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelDisconnected(channel); } }); } /** * Sends a {@code "channelDisconnected"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. */ public static void fireChannelDisconnected(Channel channel) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.CONNECTED, null)); } /** * Sends a {@code "channelDisconnected"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelDisconnected(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.CONNECTED, null)); } /** * Sends a {@code "channelUnbound"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelUnboundLater(final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelUnbound(channel); } }); } /** * Sends a {@code "channelUnbound"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. */ public static void fireChannelUnbound(Channel channel) { channel.getPipeline().sendUpstream(new UpstreamChannelStateEvent( channel, ChannelState.BOUND, null)); } /** * Sends a {@code "channelUnbound"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelUnbound(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.BOUND, null)); } /** * Sends a {@code "channelClosed"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelClosedLater(final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelClosed(channel); } }); } /** * Sends a {@code "channelClosed"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. */ public static void fireChannelClosed(Channel channel) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.OPEN, Boolean.FALSE)); // Notify the parent handler. if (channel.getParent() != null) { fireChildChannelStateChanged(channel.getParent(), channel); } } /** * Sends a {@code "channelClosed"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelClosed(ChannelHandlerContext ctx) { ctx.sendUpstream( new UpstreamChannelStateEvent( ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE)); } /** * Sends a {@code "exceptionCaught"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) { return channel.getPipeline().execute(new Runnable() { public void run() { fireExceptionCaught(channel, cause); } }); } /** * Sends a {@code "exceptionCaught"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext} once the io-thread runs again. */ public static ChannelFuture fireExceptionCaughtLater(final ChannelHandlerContext ctx, final Throwable cause) { return ctx.getPipeline().execute(new Runnable() { public void run() { fireExceptionCaught(ctx, cause); } }); } /** * Sends a {@code "exceptionCaught"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. */ public static void fireExceptionCaught(Channel channel, Throwable cause) { channel.getPipeline().sendUpstream( new DefaultExceptionEvent(channel, cause)); } /** * Sends a {@code "exceptionCaught"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireExceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.sendUpstream(new DefaultExceptionEvent(ctx.getChannel(), cause)); } private static void fireChildChannelStateChanged( Channel channel, Channel childChannel) { channel.getPipeline().sendUpstream( new DefaultChildChannelStateEvent(channel, childChannel)); } /** * Sends a {@code "bind"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to bind * @param localAddress the local address to bind to * * @return the {@link ChannelFuture} which will be notified when the * bind operation is done */ public static ChannelFuture bind(Channel channel, SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } ChannelFuture future = future(channel); channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( channel, future, ChannelState.BOUND, localAddress)); return future; } /** * Sends a {@code "bind"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified when the bind * operation is done * @param localAddress the local address to bind to */ public static void bind( ChannelHandlerContext ctx, ChannelFuture future, SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } ctx.sendDownstream(new DownstreamChannelStateEvent( ctx.getChannel(), future, ChannelState.BOUND, localAddress)); } /** * Sends a {@code "unbind"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified when the unbind * operation is done */ public static void unbind(ChannelHandlerContext ctx, ChannelFuture future) { ctx.sendDownstream(new DownstreamChannelStateEvent( ctx.getChannel(), future, ChannelState.BOUND, null)); } /** * Sends a {@code "unbind"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to unbind * * @return the {@link ChannelFuture} which will be notified when the * unbind operation is done */ public static ChannelFuture unbind(Channel channel) { ChannelFuture future = future(channel); channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( channel, future, ChannelState.BOUND, null)); return future; } /** * Sends a {@code "connect"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to attempt a connection * @param remoteAddress the remote address to connect to * * @return the {@link ChannelFuture} which will be notified when the * connection attempt is done */ public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } ChannelFuture future = future(channel, true); channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( channel, future, ChannelState.CONNECTED, remoteAddress)); return future; } /** * Sends a {@code "connect"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified when the connection * attempt is done * @param remoteAddress the remote address to connect to */ public static void connect( ChannelHandlerContext ctx, ChannelFuture future, SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } ctx.sendDownstream(new DownstreamChannelStateEvent( ctx.getChannel(), future, ChannelState.CONNECTED, remoteAddress)); } /** * Sends a {@code "write"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to write a message * @param message the message to write to the channel * * @return the {@link ChannelFuture} which will be notified when the * write operation is done */ public static ChannelFuture write(Channel channel, Object message) { return write(channel, message, null); } /** * Sends a {@code "write"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified when the write * operation is done */ public static void write( ChannelHandlerContext ctx, ChannelFuture future, Object message) { write(ctx, future, message, null); } /** * Sends a {@code "write"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to write a message * @param message the message to write to the channel * @param remoteAddress the destination of the message. * {@code null} to use the default remote address * * @return the {@link ChannelFuture} which will be notified when the * write operation is done */ public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) { ChannelFuture future = future(channel); channel.getPipeline().sendDownstream( new DownstreamMessageEvent(channel, future, message, remoteAddress)); return future; } /** * Sends a {@code "write"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified when the write * operation is done * @param message the message to write to the channel * @param remoteAddress the destination of the message. * {@code null} to use the default remote address. */ public static void write( ChannelHandlerContext ctx, ChannelFuture future, Object message, SocketAddress remoteAddress) { ctx.sendDownstream( new DownstreamMessageEvent(ctx.getChannel(), future, message, remoteAddress)); } /** * Sends a {@code "setInterestOps"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to change its interestOps * @param interestOps the new interestOps * * @return the {@link ChannelFuture} which will be notified when the * interestOps is changed */ public static ChannelFuture setInterestOps(Channel channel, int interestOps) { validateInterestOps(interestOps); interestOps = filterDownstreamInterestOps(interestOps); ChannelFuture future = future(channel); channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( channel, future, ChannelState.INTEREST_OPS, interestOps)); return future; } /** * Sends a {@code "setInterestOps"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified when the interestOps is * changed. */ public static void setInterestOps( ChannelHandlerContext ctx, ChannelFuture future, int interestOps) { validateInterestOps(interestOps); interestOps = filterDownstreamInterestOps(interestOps); ctx.sendDownstream( new DownstreamChannelStateEvent( ctx.getChannel(), future, ChannelState.INTEREST_OPS, interestOps)); } /** * Sends a {@code "disconnect"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to disconnect * * @return the {@link ChannelFuture} which will be notified on disconnection */ public static ChannelFuture disconnect(Channel channel) { ChannelFuture future = future(channel); channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( channel, future, ChannelState.CONNECTED, null)); return future; } /** * Sends a {@code "disconnect"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified on disconnection */ public static void disconnect( ChannelHandlerContext ctx, ChannelFuture future) { ctx.sendDownstream(new DownstreamChannelStateEvent( ctx.getChannel(), future, ChannelState.CONNECTED, null)); } /** * Sends a {@code "close"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. * * @param channel the channel to close * * @return the {@link ChannelFuture} which will be notified on closure */ public static ChannelFuture close(Channel channel) { ChannelFuture future = channel.getCloseFuture(); channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( channel, future, ChannelState.OPEN, Boolean.FALSE)); return future; } /** * Sends a {@code "close"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx the context * @param future the future which will be notified on closure */ public static void close( ChannelHandlerContext ctx, ChannelFuture future) { ctx.sendDownstream(new DownstreamChannelStateEvent( ctx.getChannel(), future, ChannelState.OPEN, Boolean.FALSE)); } private static void validateInterestOps(int interestOps) { switch (interestOps) { case Channel.OP_NONE: case Channel.OP_READ: case Channel.OP_WRITE: case Channel.OP_READ_WRITE: break; default: throw new IllegalArgumentException( "Invalid interestOps: " + interestOps); } } private static int filterDownstreamInterestOps(int interestOps) { return interestOps & ~Channel.OP_WRITE; } private Channels() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ChildChannelStateEvent.java000066400000000000000000000026701225554127700313760ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelEvent} which represents the notification of the state of * a child {@link Channel}. This event is for going upstream only. Please * refer to the {@link ChannelEvent} documentation to find out what an upstream * event and a downstream event are and what fundamental differences they have. */ public interface ChildChannelStateEvent extends ChannelEvent { /** * Returns the parent {@link Channel} which is associated * with this event. Please note that you should use {@link #getChildChannel()} * to get the {@link Channel} created or accepted by the parent {@link Channel}. */ Channel getChannel(); /** * Returns the child {@link Channel} whose state has been changed. */ Channel getChildChannel(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/CompleteChannelFuture.java000066400000000000000000000063541225554127700313160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.util.concurrent.TimeUnit; /** * A skeletal {@link ChannelFuture} implementation which represents a * {@link ChannelFuture} which has been completed already. */ public abstract class CompleteChannelFuture implements ChannelFuture { private static final InternalLogger logger = InternalLoggerFactory.getInstance(CompleteChannelFuture.class); private final Channel channel; /** * Creates a new instance. * * @param channel the {@link Channel} associated with this future */ protected CompleteChannelFuture(Channel channel) { if (channel == null) { throw new NullPointerException("channel"); } this.channel = channel; } public void addListener(ChannelFutureListener listener) { try { listener.operationComplete(this); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn( "An exception was thrown by " + ChannelFutureListener.class.getSimpleName() + '.', t); } } } public void removeListener(ChannelFutureListener listener) { // NOOP } public ChannelFuture await() throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } return this; } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } return true; } public boolean await(long timeoutMillis) throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } return true; } public ChannelFuture awaitUninterruptibly() { return this; } public boolean awaitUninterruptibly(long timeout, TimeUnit unit) { return true; } public boolean awaitUninterruptibly(long timeoutMillis) { return true; } public Channel getChannel() { return channel; } public boolean isDone() { return true; } public boolean setProgress(long amount, long current, long total) { return false; } public boolean setFailure(Throwable cause) { return false; } public boolean setSuccess() { return false; } public boolean cancel() { return false; } public boolean isCancelled() { return false; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ConnectTimeoutException.java000066400000000000000000000021111225554127700316640ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.ConnectException; /** * {@link ConnectException} which will be thrown if a connection could * not be established because of a connection timeout. */ public class ConnectTimeoutException extends ConnectException { private static final long serialVersionUID = 2317065249988317463L; public ConnectTimeoutException(String msg) { super(msg); } public ConnectTimeoutException() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultChannelConfig.java000066400000000000000000000054621225554127700310640ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.HeapChannelBufferFactory; import org.jboss.netty.channel.socket.SocketChannelConfig; import org.jboss.netty.util.internal.ConversionUtil; import java.util.Map; import java.util.Map.Entry; /** * The default {@link SocketChannelConfig} implementation. */ public class DefaultChannelConfig implements ChannelConfig { private volatile ChannelBufferFactory bufferFactory = HeapChannelBufferFactory.getInstance(); private volatile int connectTimeoutMillis = 10000; // 10 seconds public void setOptions(Map options) { for (Entry e: options.entrySet()) { setOption(e.getKey(), e.getValue()); } } public boolean setOption(String key, Object value) { if (key == null) { throw new NullPointerException("key"); } if ("pipelineFactory".equals(key)) { setPipelineFactory((ChannelPipelineFactory) value); } else if ("connectTimeoutMillis".equals(key)) { setConnectTimeoutMillis(ConversionUtil.toInt(value)); } else if ("bufferFactory".equals(key)) { setBufferFactory((ChannelBufferFactory) value); } else { return false; } return true; } public int getConnectTimeoutMillis() { return connectTimeoutMillis; } public ChannelBufferFactory getBufferFactory() { return bufferFactory; } public void setBufferFactory(ChannelBufferFactory bufferFactory) { if (bufferFactory == null) { throw new NullPointerException("bufferFactory"); } this.bufferFactory = bufferFactory; } public ChannelPipelineFactory getPipelineFactory() { return null; } public void setConnectTimeoutMillis(int connectTimeoutMillis) { if (connectTimeoutMillis < 0) { throw new IllegalArgumentException("connectTimeoutMillis: " + connectTimeoutMillis); } this.connectTimeoutMillis = connectTimeoutMillis; } public void setPipelineFactory(ChannelPipelineFactory pipelineFactory) { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultChannelFuture.java000066400000000000000000000336361225554127700311350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.DeadLockProofWorker; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; import static java.util.concurrent.TimeUnit.*; /** * The default {@link ChannelFuture} implementation. It is recommended to * use {@link Channels#future(Channel)} and {@link Channels#future(Channel, boolean)} * to create a new {@link ChannelFuture} rather than calling the constructor * explicitly. */ public class DefaultChannelFuture implements ChannelFuture { private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelFuture.class); private static final Throwable CANCELLED = new Throwable(); private static volatile boolean useDeadLockChecker = true; private static boolean disabledDeadLockCheckerOnce; /** * Returns {@code true} if and only if the dead lock checker is enabled. */ public static boolean isUseDeadLockChecker() { return useDeadLockChecker; } /** * Enables or disables the dead lock checker. It is not recommended to * disable the dead lock checker. Disable it at your own risk! */ public static void setUseDeadLockChecker(boolean useDeadLockChecker) { if (!useDeadLockChecker && !disabledDeadLockCheckerOnce) { disabledDeadLockCheckerOnce = true; if (logger.isDebugEnabled()) { logger.debug( "The dead lock checker in " + DefaultChannelFuture.class.getSimpleName() + " has been disabled as requested at your own risk."); } } DefaultChannelFuture.useDeadLockChecker = useDeadLockChecker; } private final Channel channel; private final boolean cancellable; private ChannelFutureListener firstListener; private List otherListeners; private List progressListeners; private boolean done; private Throwable cause; private int waiters; /** * Creates a new instance. * * @param channel * the {@link Channel} associated with this future * @param cancellable * {@code true} if and only if this future can be canceled */ public DefaultChannelFuture(Channel channel, boolean cancellable) { this.channel = channel; this.cancellable = cancellable; } public Channel getChannel() { return channel; } public synchronized boolean isDone() { return done; } public synchronized boolean isSuccess() { return done && cause == null; } public synchronized Throwable getCause() { if (cause != CANCELLED) { return cause; } else { return null; } } public synchronized boolean isCancelled() { return cause == CANCELLED; } public void addListener(ChannelFutureListener listener) { if (listener == null) { throw new NullPointerException("listener"); } boolean notifyNow = false; synchronized (this) { if (done) { notifyNow = true; } else { if (firstListener == null) { firstListener = listener; } else { if (otherListeners == null) { otherListeners = new ArrayList(1); } otherListeners.add(listener); } if (listener instanceof ChannelFutureProgressListener) { if (progressListeners == null) { progressListeners = new ArrayList(1); } progressListeners.add((ChannelFutureProgressListener) listener); } } } if (notifyNow) { notifyListener(listener); } } public void removeListener(ChannelFutureListener listener) { if (listener == null) { throw new NullPointerException("listener"); } synchronized (this) { if (!done) { if (listener == firstListener) { if (otherListeners != null && !otherListeners.isEmpty()) { firstListener = otherListeners.remove(0); } else { firstListener = null; } } else if (otherListeners != null) { otherListeners.remove(listener); } if (listener instanceof ChannelFutureProgressListener) { progressListeners.remove(listener); } } } } @Deprecated public ChannelFuture rethrowIfFailed() throws Exception { if (!isDone()) { return this; } Throwable cause = getCause(); if (cause == null) { return this; } if (cause instanceof Exception) { throw (Exception) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(cause); } public ChannelFuture sync() throws InterruptedException { await(); rethrowIfFailed0(); return this; } public ChannelFuture syncUninterruptibly() { awaitUninterruptibly(); rethrowIfFailed0(); return this; } private void rethrowIfFailed0() { Throwable cause = getCause(); if (cause == null) { return; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new ChannelException(cause); } public ChannelFuture await() throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } synchronized (this) { while (!done) { checkDeadLock(); waiters++; try { wait(); } finally { waiters--; } } } return this; } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return await0(unit.toNanos(timeout), true); } public boolean await(long timeoutMillis) throws InterruptedException { return await0(MILLISECONDS.toNanos(timeoutMillis), true); } public ChannelFuture awaitUninterruptibly() { boolean interrupted = false; synchronized (this) { while (!done) { checkDeadLock(); waiters++; try { wait(); } catch (InterruptedException e) { interrupted = true; } finally { waiters--; } } } if (interrupted) { Thread.currentThread().interrupt(); } return this; } public boolean awaitUninterruptibly(long timeout, TimeUnit unit) { try { return await0(unit.toNanos(timeout), false); } catch (InterruptedException e) { throw new InternalError(); } } public boolean awaitUninterruptibly(long timeoutMillis) { try { return await0(MILLISECONDS.toNanos(timeoutMillis), false); } catch (InterruptedException e) { throw new InternalError(); } } private boolean await0(long timeoutNanos, boolean interruptable) throws InterruptedException { if (interruptable && Thread.interrupted()) { throw new InterruptedException(); } long startTime = timeoutNanos <= 0 ? 0 : System.nanoTime(); long waitTime = timeoutNanos; boolean interrupted = false; try { synchronized (this) { if (done || waitTime <= 0) { return done; } checkDeadLock(); waiters++; try { for (;;) { try { wait(waitTime / 1000000, (int) (waitTime % 1000000)); } catch (InterruptedException e) { if (interruptable) { throw e; } else { interrupted = true; } } if (done) { return true; } else { waitTime = timeoutNanos - (System.nanoTime() - startTime); if (waitTime <= 0) { return done; } } } } finally { waiters--; } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } private static void checkDeadLock() { if (isUseDeadLockChecker() && DeadLockProofWorker.PARENT.get() != null) { throw new IllegalStateException( "await*() in I/O thread causes a dead lock or " + "sudden performance drop. Use addListener() instead or " + "call await*() from a different thread."); } } public boolean setSuccess() { synchronized (this) { // Allow only once. if (done) { return false; } done = true; if (waiters > 0) { notifyAll(); } } notifyListeners(); return true; } public boolean setFailure(Throwable cause) { synchronized (this) { // Allow only once. if (done) { return false; } this.cause = cause; done = true; if (waiters > 0) { notifyAll(); } } notifyListeners(); return true; } public boolean cancel() { if (!cancellable) { return false; } synchronized (this) { // Allow only once. if (done) { return false; } cause = CANCELLED; done = true; if (waiters > 0) { notifyAll(); } } notifyListeners(); return true; } private void notifyListeners() { // This method doesn't need synchronization because: // 1) This method is always called after synchronized (this) block. // Hence any listener list modification happens-before this method. // 2) This method is called only when 'done' is true. Once 'done' // becomes true, the listener list is never modified - see add/removeListener() if (firstListener != null) { notifyListener(firstListener); firstListener = null; if (otherListeners != null) { for (ChannelFutureListener l: otherListeners) { notifyListener(l); } otherListeners = null; } } } private void notifyListener(ChannelFutureListener l) { try { l.operationComplete(this); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn( "An exception was thrown by " + ChannelFutureListener.class.getSimpleName() + '.', t); } } } public boolean setProgress(long amount, long current, long total) { ChannelFutureProgressListener[] plisteners; synchronized (this) { // Do not generate progress event after completion. if (done) { return false; } Collection progressListeners = this.progressListeners; if (progressListeners == null || progressListeners.isEmpty()) { // Nothing to notify - no need to create an empty array. return true; } plisteners = progressListeners.toArray( new ChannelFutureProgressListener[progressListeners.size()]); } for (ChannelFutureProgressListener pl: plisteners) { notifyProgressListener(pl, amount, current, total); } return true; } private void notifyProgressListener( ChannelFutureProgressListener l, long amount, long current, long total) { try { l.operationProgressed(this, amount, current, total); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn( "An exception was thrown by " + ChannelFutureProgressListener.class.getSimpleName() + '.', t); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultChannelPipeline.java000066400000000000000000000625631225554127700314310ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.RejectedExecutionException; /** * The default {@link ChannelPipeline} implementation. It is recommended * to use {@link Channels#pipeline()} to create a new {@link ChannelPipeline} * instance rather than calling the constructor directly. */ public class DefaultChannelPipeline implements ChannelPipeline { static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class); static final ChannelSink discardingSink = new DiscardingChannelSink(); private volatile Channel channel; private volatile ChannelSink sink; private volatile DefaultChannelHandlerContext head; private volatile DefaultChannelHandlerContext tail; private final Map name2ctx = new HashMap(4); public Channel getChannel() { return channel; } public ChannelSink getSink() { ChannelSink sink = this.sink; if (sink == null) { return discardingSink; } return sink; } public void attach(Channel channel, ChannelSink sink) { if (channel == null) { throw new NullPointerException("channel"); } if (sink == null) { throw new NullPointerException("sink"); } if (this.channel != null || this.sink != null) { throw new IllegalStateException("attached already"); } this.channel = channel; this.sink = sink; } public boolean isAttached() { return sink != null; } public synchronized void addFirst(String name, ChannelHandler handler) { if (name2ctx.isEmpty()) { init(name, handler); } else { checkDuplicateName(name); DefaultChannelHandlerContext oldHead = head; DefaultChannelHandlerContext newHead = new DefaultChannelHandlerContext(null, oldHead, name, handler); callBeforeAdd(newHead); oldHead.prev = newHead; head = newHead; name2ctx.put(name, newHead); callAfterAdd(newHead); } } public synchronized void addLast(String name, ChannelHandler handler) { if (name2ctx.isEmpty()) { init(name, handler); } else { checkDuplicateName(name); DefaultChannelHandlerContext oldTail = tail; DefaultChannelHandlerContext newTail = new DefaultChannelHandlerContext(oldTail, null, name, handler); callBeforeAdd(newTail); oldTail.next = newTail; tail = newTail; name2ctx.put(name, newTail); callAfterAdd(newTail); } } public synchronized void addBefore(String baseName, String name, ChannelHandler handler) { DefaultChannelHandlerContext ctx = getContextOrDie(baseName); if (ctx == head) { addFirst(name, handler); } else { checkDuplicateName(name); DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx.prev, ctx, name, handler); callBeforeAdd(newCtx); ctx.prev.next = newCtx; ctx.prev = newCtx; name2ctx.put(name, newCtx); callAfterAdd(newCtx); } } public synchronized void addAfter(String baseName, String name, ChannelHandler handler) { DefaultChannelHandlerContext ctx = getContextOrDie(baseName); if (ctx == tail) { addLast(name, handler); } else { checkDuplicateName(name); DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx, ctx.next, name, handler); callBeforeAdd(newCtx); ctx.next.prev = newCtx; ctx.next = newCtx; name2ctx.put(name, newCtx); callAfterAdd(newCtx); } } public synchronized void remove(ChannelHandler handler) { remove(getContextOrDie(handler)); } public synchronized ChannelHandler remove(String name) { return remove(getContextOrDie(name)).getHandler(); } @SuppressWarnings("unchecked") public synchronized T remove(Class handlerType) { return (T) remove(getContextOrDie(handlerType)).getHandler(); } private DefaultChannelHandlerContext remove(DefaultChannelHandlerContext ctx) { if (head == tail) { callBeforeRemove(ctx); head = tail = null; name2ctx.clear(); callAfterRemove(ctx); } else if (ctx == head) { removeFirst(); } else if (ctx == tail) { removeLast(); } else { callBeforeRemove(ctx); DefaultChannelHandlerContext prev = ctx.prev; DefaultChannelHandlerContext next = ctx.next; prev.next = next; next.prev = prev; name2ctx.remove(ctx.getName()); callAfterRemove(ctx); } return ctx; } public synchronized ChannelHandler removeFirst() { if (name2ctx.isEmpty()) { throw new NoSuchElementException(); } DefaultChannelHandlerContext oldHead = head; if (oldHead == null) { throw new NoSuchElementException(); } callBeforeRemove(oldHead); if (oldHead.next == null) { head = tail = null; name2ctx.clear(); } else { oldHead.next.prev = null; head = oldHead.next; name2ctx.remove(oldHead.getName()); } callAfterRemove(oldHead); return oldHead.getHandler(); } public synchronized ChannelHandler removeLast() { if (name2ctx.isEmpty()) { throw new NoSuchElementException(); } DefaultChannelHandlerContext oldTail = tail; if (oldTail == null) { throw new NoSuchElementException(); } callBeforeRemove(oldTail); if (oldTail.prev == null) { head = tail = null; name2ctx.clear(); } else { oldTail.prev.next = null; tail = oldTail.prev; name2ctx.remove(oldTail.getName()); } callAfterRemove(oldTail); return oldTail.getHandler(); } public synchronized void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler) { replace(getContextOrDie(oldHandler), newName, newHandler); } public synchronized ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler) { return replace(getContextOrDie(oldName), newName, newHandler); } @SuppressWarnings("unchecked") public synchronized T replace( Class oldHandlerType, String newName, ChannelHandler newHandler) { return (T) replace(getContextOrDie(oldHandlerType), newName, newHandler); } private ChannelHandler replace(DefaultChannelHandlerContext ctx, String newName, ChannelHandler newHandler) { if (ctx == head) { removeFirst(); addFirst(newName, newHandler); } else if (ctx == tail) { removeLast(); addLast(newName, newHandler); } else { boolean sameName = ctx.getName().equals(newName); if (!sameName) { checkDuplicateName(newName); } DefaultChannelHandlerContext prev = ctx.prev; DefaultChannelHandlerContext next = ctx.next; DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(prev, next, newName, newHandler); callBeforeRemove(ctx); callBeforeAdd(newCtx); prev.next = newCtx; next.prev = newCtx; if (!sameName) { name2ctx.remove(ctx.getName()); } name2ctx.put(newName, newCtx); ChannelHandlerLifeCycleException removeException = null; ChannelHandlerLifeCycleException addException = null; boolean removed = false; try { callAfterRemove(ctx); removed = true; } catch (ChannelHandlerLifeCycleException e) { removeException = e; } boolean added = false; try { callAfterAdd(newCtx); added = true; } catch (ChannelHandlerLifeCycleException e) { addException = e; } if (!removed && !added) { logger.warn(removeException.getMessage(), removeException); logger.warn(addException.getMessage(), addException); throw new ChannelHandlerLifeCycleException( "Both " + ctx.getHandler().getClass().getName() + ".afterRemove() and " + newCtx.getHandler().getClass().getName() + ".afterAdd() failed; see logs."); } else if (!removed) { throw removeException; } else if (!added) { throw addException; } } return ctx.getHandler(); } private static void callBeforeAdd(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.beforeAdd(ctx); } catch (Throwable t) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".beforeAdd() has thrown an exception; not adding.", t); } } private void callAfterAdd(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.afterAdd(ctx); } catch (Throwable t) { boolean removed = false; try { remove((DefaultChannelHandlerContext) ctx); removed = true; } catch (Throwable t2) { if (logger.isWarnEnabled()) { logger.warn("Failed to remove a handler: " + ctx.getName(), t2); } } if (removed) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".afterAdd() has thrown an exception; removed.", t); } else { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".afterAdd() has thrown an exception; also failed to remove.", t); } } } private static void callBeforeRemove(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.beforeRemove(ctx); } catch (Throwable t) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".beforeRemove() has thrown an exception; not removing.", t); } } private static void callAfterRemove(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.afterRemove(ctx); } catch (Throwable t) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".afterRemove() has thrown an exception.", t); } } public synchronized ChannelHandler getFirst() { DefaultChannelHandlerContext head = this.head; if (head == null) { return null; } return head.getHandler(); } public synchronized ChannelHandler getLast() { DefaultChannelHandlerContext tail = this.tail; if (tail == null) { return null; } return tail.getHandler(); } public synchronized ChannelHandler get(String name) { DefaultChannelHandlerContext ctx = name2ctx.get(name); if (ctx == null) { return null; } else { return ctx.getHandler(); } } public synchronized T get(Class handlerType) { ChannelHandlerContext ctx = getContext(handlerType); if (ctx == null) { return null; } else { @SuppressWarnings("unchecked") T handler = (T) ctx.getHandler(); return handler; } } public synchronized ChannelHandlerContext getContext(String name) { if (name == null) { throw new NullPointerException("name"); } return name2ctx.get(name); } public synchronized ChannelHandlerContext getContext(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } if (name2ctx.isEmpty()) { return null; } DefaultChannelHandlerContext ctx = head; for (;;) { if (ctx.getHandler() == handler) { return ctx; } ctx = ctx.next; if (ctx == null) { break; } } return null; } public synchronized ChannelHandlerContext getContext( Class handlerType) { if (handlerType == null) { throw new NullPointerException("handlerType"); } if (name2ctx.isEmpty()) { return null; } DefaultChannelHandlerContext ctx = head; for (;;) { if (handlerType.isAssignableFrom(ctx.getHandler().getClass())) { return ctx; } ctx = ctx.next; if (ctx == null) { break; } } return null; } public List getNames() { List list = new ArrayList(); if (name2ctx.isEmpty()) { return list; } DefaultChannelHandlerContext ctx = head; for (;;) { list.add(ctx.getName()); ctx = ctx.next; if (ctx == null) { break; } } return list; } public Map toMap() { Map map = new LinkedHashMap(); if (name2ctx.isEmpty()) { return map; } DefaultChannelHandlerContext ctx = head; for (;;) { map.put(ctx.getName(), ctx.getHandler()); ctx = ctx.next; if (ctx == null) { break; } } return map; } /** * Returns the {@link String} representation of this pipeline. */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append('{'); DefaultChannelHandlerContext ctx = head; if (ctx != null) { for (;;) { buf.append('('); buf.append(ctx.getName()); buf.append(" = "); buf.append(ctx.getHandler().getClass().getName()); buf.append(')'); ctx = ctx.next; if (ctx == null) { break; } buf.append(", "); } } buf.append('}'); return buf.toString(); } public void sendUpstream(ChannelEvent e) { DefaultChannelHandlerContext head = getActualUpstreamContext(this.head); if (head == null) { if (logger.isWarnEnabled()) { logger.warn( "The pipeline contains no upstream handlers; discarding: " + e); } return; } sendUpstream(head, e); } void sendUpstream(DefaultChannelHandlerContext ctx, ChannelEvent e) { try { ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e); } catch (Throwable t) { notifyHandlerException(e, t); } } public void sendDownstream(ChannelEvent e) { DefaultChannelHandlerContext tail = getActualDownstreamContext(this.tail); if (tail == null) { try { getSink().eventSunk(this, e); return; } catch (Throwable t) { notifyHandlerException(e, t); return; } } sendDownstream(tail, e); } void sendDownstream(DefaultChannelHandlerContext ctx, ChannelEvent e) { if (e instanceof UpstreamMessageEvent) { throw new IllegalArgumentException("cannot send an upstream event to downstream"); } try { ((ChannelDownstreamHandler) ctx.getHandler()).handleDownstream(ctx, e); } catch (Throwable t) { // Unlike an upstream event, a downstream event usually has an // incomplete future which is supposed to be updated by ChannelSink. // However, if an exception is raised before the event reaches at // ChannelSink, the future is not going to be updated, so we update // here. e.getFuture().setFailure(t); notifyHandlerException(e, t); } } private DefaultChannelHandlerContext getActualUpstreamContext(DefaultChannelHandlerContext ctx) { if (ctx == null) { return null; } DefaultChannelHandlerContext realCtx = ctx; while (!realCtx.canHandleUpstream()) { realCtx = realCtx.next; if (realCtx == null) { return null; } } return realCtx; } private DefaultChannelHandlerContext getActualDownstreamContext(DefaultChannelHandlerContext ctx) { if (ctx == null) { return null; } DefaultChannelHandlerContext realCtx = ctx; while (!realCtx.canHandleDownstream()) { realCtx = realCtx.prev; if (realCtx == null) { return null; } } return realCtx; } public ChannelFuture execute(Runnable task) { return getSink().execute(this, task); } protected void notifyHandlerException(ChannelEvent e, Throwable t) { if (e instanceof ExceptionEvent) { if (logger.isWarnEnabled()) { logger.warn( "An exception was thrown by a user handler " + "while handling an exception event (" + e + ')', t); } return; } ChannelPipelineException pe; if (t instanceof ChannelPipelineException) { pe = (ChannelPipelineException) t; } else { pe = new ChannelPipelineException(t); } try { sink.exceptionCaught(this, e, pe); } catch (Exception e1) { if (logger.isWarnEnabled()) { logger.warn("An exception was thrown by an exception handler.", e1); } } } private void init(String name, ChannelHandler handler) { DefaultChannelHandlerContext ctx = new DefaultChannelHandlerContext(null, null, name, handler); callBeforeAdd(ctx); head = tail = ctx; name2ctx.clear(); name2ctx.put(name, ctx); callAfterAdd(ctx); } private void checkDuplicateName(String name) { if (name2ctx.containsKey(name)) { throw new IllegalArgumentException("Duplicate handler name: " + name); } } private DefaultChannelHandlerContext getContextOrDie(String name) { DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) getContext(name); if (ctx == null) { throw new NoSuchElementException(name); } else { return ctx; } } private DefaultChannelHandlerContext getContextOrDie(ChannelHandler handler) { DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) getContext(handler); if (ctx == null) { throw new NoSuchElementException(handler.getClass().getName()); } else { return ctx; } } private DefaultChannelHandlerContext getContextOrDie(Class handlerType) { DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) getContext(handlerType); if (ctx == null) { throw new NoSuchElementException(handlerType.getName()); } else { return ctx; } } private final class DefaultChannelHandlerContext implements ChannelHandlerContext { volatile DefaultChannelHandlerContext next; volatile DefaultChannelHandlerContext prev; private final String name; private final ChannelHandler handler; private final boolean canHandleUpstream; private final boolean canHandleDownstream; private volatile Object attachment; DefaultChannelHandlerContext( DefaultChannelHandlerContext prev, DefaultChannelHandlerContext next, String name, ChannelHandler handler) { if (name == null) { throw new NullPointerException("name"); } if (handler == null) { throw new NullPointerException("handler"); } canHandleUpstream = handler instanceof ChannelUpstreamHandler; canHandleDownstream = handler instanceof ChannelDownstreamHandler; if (!canHandleUpstream && !canHandleDownstream) { throw new IllegalArgumentException( "handler must be either " + ChannelUpstreamHandler.class.getName() + " or " + ChannelDownstreamHandler.class.getName() + '.'); } this.prev = prev; this.next = next; this.name = name; this.handler = handler; } public Channel getChannel() { return getPipeline().getChannel(); } public ChannelPipeline getPipeline() { return DefaultChannelPipeline.this; } public boolean canHandleDownstream() { return canHandleDownstream; } public boolean canHandleUpstream() { return canHandleUpstream; } public ChannelHandler getHandler() { return handler; } public String getName() { return name; } public Object getAttachment() { return attachment; } public void setAttachment(Object attachment) { this.attachment = attachment; } public void sendDownstream(ChannelEvent e) { DefaultChannelHandlerContext prev = getActualDownstreamContext(this.prev); if (prev == null) { try { getSink().eventSunk(DefaultChannelPipeline.this, e); } catch (Throwable t) { notifyHandlerException(e, t); } } else { DefaultChannelPipeline.this.sendDownstream(prev, e); } } public void sendUpstream(ChannelEvent e) { DefaultChannelHandlerContext next = getActualUpstreamContext(this.next); if (next != null) { DefaultChannelPipeline.this.sendUpstream(next, e); } } } private static final class DiscardingChannelSink implements ChannelSink { DiscardingChannelSink() { } public void eventSunk(ChannelPipeline pipeline, ChannelEvent e) { if (logger.isWarnEnabled()) { logger.warn("Not attached yet; discarding: " + e); } } public void exceptionCaught(ChannelPipeline pipeline, ChannelEvent e, ChannelPipelineException cause) throws Exception { throw cause; } public ChannelFuture execute(ChannelPipeline pipeline, Runnable task) { if (logger.isWarnEnabled()) { logger.warn("Not attached yet; rejecting: " + task); } return Channels.failedFuture(pipeline.getChannel(), new RejectedExecutionException("Not attached yet")); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultChildChannelStateEvent.java000066400000000000000000000037371225554127700327100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.jboss.netty.channel.Channels.*; /** * The default {@link ChildChannelStateEvent} implementation. */ public class DefaultChildChannelStateEvent implements ChildChannelStateEvent { private final Channel parentChannel; private final Channel childChannel; /** * Creates a new instance. */ public DefaultChildChannelStateEvent(Channel parentChannel, Channel childChannel) { if (parentChannel == null) { throw new NullPointerException("parentChannel"); } if (childChannel == null) { throw new NullPointerException("childChannel"); } this.parentChannel = parentChannel; this.childChannel = childChannel; } public Channel getChannel() { return parentChannel; } public ChannelFuture getFuture() { return succeededFuture(getChannel()); } public Channel getChildChannel() { return childChannel; } @Override public String toString() { String channelString = getChannel().toString(); StringBuilder buf = new StringBuilder(channelString.length() + 32); buf.append(channelString); buf.append(getChildChannel().isOpen()? " CHILD_OPEN: " : " CHILD_CLOSED: "); buf.append(getChildChannel().getId()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultExceptionEvent.java000066400000000000000000000033041225554127700313170ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.util.internal.StackTraceSimplifier; /** * The default {@link ExceptionEvent} implementation. */ public class DefaultExceptionEvent implements ExceptionEvent { private final Channel channel; private final Throwable cause; /** * Creates a new instance. */ public DefaultExceptionEvent(Channel channel, Throwable cause) { if (channel == null) { throw new NullPointerException("channel"); } if (cause == null) { throw new NullPointerException("cause"); } this.channel = channel; this.cause = cause; StackTraceSimplifier.simplify(cause); } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return succeededFuture(getChannel()); } public Throwable getCause() { return cause; } @Override public String toString() { return getChannel().toString() + " EXCEPTION: " + cause; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultFileRegion.java000066400000000000000000000047611225554127700304120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; public class DefaultFileRegion implements FileRegion { private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultFileRegion.class); private final FileChannel file; private final long position; private final long count; private final boolean releaseAfterTransfer; public DefaultFileRegion(FileChannel file, long position, long count) { this(file, position, count, false); } public DefaultFileRegion(FileChannel file, long position, long count, boolean releaseAfterTransfer) { this.file = file; this.position = position; this.count = count; this.releaseAfterTransfer = releaseAfterTransfer; } public long getPosition() { return position; } public long getCount() { return count; } public boolean releaseAfterTransfer() { return releaseAfterTransfer; } public long transferTo(WritableByteChannel target, long position) throws IOException { long count = this.count - position; if (count < 0 || position < 0) { throw new IllegalArgumentException( "position out of range: " + position + " (expected: 0 - " + (this.count - 1) + ')'); } if (count == 0) { return 0L; } return file.transferTo(this.position + position, count, target); } public void releaseExternalResources() { try { file.close(); } catch (IOException e) { if (logger.isWarnEnabled()) { logger.warn("Failed to close a file.", e); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultServerChannelConfig.java000066400000000000000000000053361225554127700322530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.HeapChannelBufferFactory; import org.jboss.netty.channel.socket.ServerSocketChannelConfig; import java.util.Map; import java.util.Map.Entry; /** * The default {@link ServerSocketChannelConfig} implementation. */ public class DefaultServerChannelConfig implements ChannelConfig { private volatile ChannelPipelineFactory pipelineFactory; private volatile ChannelBufferFactory bufferFactory = HeapChannelBufferFactory.getInstance(); public void setOptions(Map options) { for (Entry e: options.entrySet()) { setOption(e.getKey(), e.getValue()); } } /** * Sets an individual option. You can override this method to support * additional configuration parameters. */ public boolean setOption(String key, Object value) { if (key == null) { throw new NullPointerException("key"); } if ("pipelineFactory".equals(key)) { setPipelineFactory((ChannelPipelineFactory) value); } else if ("bufferFactory".equals(key)) { setBufferFactory((ChannelBufferFactory) value); } else { return false; } return true; } public ChannelPipelineFactory getPipelineFactory() { return pipelineFactory; } public void setPipelineFactory(ChannelPipelineFactory pipelineFactory) { if (pipelineFactory == null) { throw new NullPointerException("pipelineFactory"); } this.pipelineFactory = pipelineFactory; } public ChannelBufferFactory getBufferFactory() { return bufferFactory; } public void setBufferFactory(ChannelBufferFactory bufferFactory) { if (bufferFactory == null) { throw new NullPointerException("bufferFactory"); } this.bufferFactory = bufferFactory; } public int getConnectTimeoutMillis() { return 0; } public void setConnectTimeoutMillis(int connectTimeoutMillis) { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DefaultWriteCompletionEvent.java000066400000000000000000000036751225554127700325200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.jboss.netty.channel.Channels.*; /** * The default {@link WriteCompletionEvent} implementation. */ public class DefaultWriteCompletionEvent implements WriteCompletionEvent { private final Channel channel; private final long writtenAmount; /** * Creates a new instance. */ public DefaultWriteCompletionEvent(Channel channel, long writtenAmount) { if (channel == null) { throw new NullPointerException("channel"); } if (writtenAmount <= 0) { throw new IllegalArgumentException( "writtenAmount must be a positive integer: " + writtenAmount); } this.channel = channel; this.writtenAmount = writtenAmount; } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return succeededFuture(getChannel()); } public long getWrittenAmount() { return writtenAmount; } @Override public String toString() { String channelString = getChannel().toString(); StringBuilder buf = new StringBuilder(channelString.length() + 32); buf.append(channelString); buf.append(" WRITTEN_AMOUNT: "); buf.append(getWrittenAmount()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DownstreamChannelStateEvent.java000066400000000000000000000057661225554127700325070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * The default downstream {@link ChannelStateEvent} implementation. */ public class DownstreamChannelStateEvent implements ChannelStateEvent { private final Channel channel; private final ChannelFuture future; private final ChannelState state; private final Object value; /** * Creates a new instance. */ public DownstreamChannelStateEvent( Channel channel, ChannelFuture future, ChannelState state, Object value) { if (channel == null) { throw new NullPointerException("channel"); } if (future == null) { throw new NullPointerException("future"); } if (state == null) { throw new NullPointerException("state"); } this.channel = channel; this.future = future; this.state = state; this.value = value; } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return future; } public ChannelState getState() { return state; } public Object getValue() { return value; } @Override public String toString() { String channelString = getChannel().toString(); StringBuilder buf = new StringBuilder(channelString.length() + 64); buf.append(channelString); switch (getState()) { case OPEN: if (Boolean.TRUE.equals(getValue())) { buf.append(" OPEN"); } else { buf.append(" CLOSE"); } break; case BOUND: if (getValue() != null) { buf.append(" BIND: "); buf.append(getValue()); } else { buf.append(" UNBIND"); } break; case CONNECTED: if (getValue() != null) { buf.append(" CONNECT: "); buf.append(getValue()); } else { buf.append(" DISCONNECT"); } break; case INTEREST_OPS: buf.append(" CHANGE_INTEREST: "); buf.append(getValue()); break; default: buf.append(' '); buf.append(getState().name()); buf.append(": "); buf.append(getValue()); } return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/DownstreamMessageEvent.java000066400000000000000000000047361225554127700315160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; import org.jboss.netty.util.internal.StringUtil; /** * The default downstream {@link MessageEvent} implementation. */ public class DownstreamMessageEvent implements MessageEvent { private final Channel channel; private final ChannelFuture future; private final Object message; private final SocketAddress remoteAddress; /** * Creates a new instance. */ public DownstreamMessageEvent( Channel channel, ChannelFuture future, Object message, SocketAddress remoteAddress) { if (channel == null) { throw new NullPointerException("channel"); } if (future == null) { throw new NullPointerException("future"); } if (message == null) { throw new NullPointerException("message"); } this.channel = channel; this.future = future; this.message = message; if (remoteAddress != null) { this.remoteAddress = remoteAddress; } else { this.remoteAddress = channel.getRemoteAddress(); } } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return future; } public Object getMessage() { return message; } public SocketAddress getRemoteAddress() { return remoteAddress; } @Override public String toString() { if (getRemoteAddress() == getChannel().getRemoteAddress()) { return getChannel().toString() + " WRITE: " + StringUtil.stripControlCharacters(getMessage()); } else { return getChannel().toString() + " WRITE: " + StringUtil.stripControlCharacters(getMessage()) + " to " + getRemoteAddress(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ExceptionEvent.java000066400000000000000000000022051225554127700300110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelEvent} which represents the notification of an exception * raised by a {@link ChannelHandler} or an I/O thread. This event is for * going upstream only. Please refer to the {@link ChannelEvent} documentation * to find out what an upstream event and a downstream event are and what * fundamental differences they have. */ public interface ExceptionEvent extends ChannelEvent { /** * Returns the raised exception. */ Throwable getCause(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/FailedChannelFuture.java000066400000000000000000000043171225554127700307270ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * The {@link CompleteChannelFuture} which is failed already. It is * recommended to use {@link Channels#failedFuture(Channel, Throwable)} * instead of calling the constructor of this future. */ public class FailedChannelFuture extends CompleteChannelFuture { private final Throwable cause; /** * Creates a new instance. * * @param channel the {@link Channel} associated with this future * @param cause the cause of failure */ public FailedChannelFuture(Channel channel, Throwable cause) { super(channel); if (cause == null) { throw new NullPointerException("cause"); } this.cause = cause; } public Throwable getCause() { return cause; } public boolean isSuccess() { return false; } @Deprecated public ChannelFuture rethrowIfFailed() throws Exception { if (cause instanceof Exception) { throw (Exception) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(cause); } public ChannelFuture sync() throws InterruptedException { rethrow(); return this; } public ChannelFuture syncUninterruptibly() { rethrow(); return this; } private void rethrow() { if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new ChannelException(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/FileRegion.java000066400000000000000000000070311225554127700270760ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; import org.jboss.netty.util.ExternalResourceReleasable; /** * A region of a file that is sent via a {@link Channel} which supports * zero-copy file transfer. * *

Upgrade your JDK / JRE

* * {@link FileChannel#transferTo(long, long, WritableByteChannel)} has at least * four known bugs in the old versions of Sun JDK and perhaps its derived ones. * Please upgrade your JDK to 1.6.0_18 or later version if you are going to use * zero-copy file transfer. *
    *
  • 5103988 * - FileChannel.transferTo() should return -1 for EAGAIN instead throws IOException
  • *
  • 6253145 * - FileChannel.transferTo() on Linux fails when going beyond 2GB boundary
  • *
  • 6427312 * - FileChannel.transferTo() throws IOException "system call interrupted"
  • *
  • 6470086 * - FileChannel.transferTo(2147483647, 1, channel) causes "Value too large" exception
  • *
* *

Check your operating system and JDK / JRE

* * If your operating system (or JDK / JRE) does not support zero-copy file * transfer, sending a file with {@link FileRegion} might fail or yield worse * performance. For example, sending a large file doesn't work well in Windows. * *

Not all transports support it

* * Currently, the NIO transport is the only transport that supports {@link FileRegion}. * Attempting to write a {@link FileRegion} to non-NIO {@link Channel} will trigger * a {@link ClassCastException} or a similar exception. */ public interface FileRegion extends ExternalResourceReleasable { // FIXME Make sure all transports support writing a FileRegion // Even if zero copy cannot be achieved, all transports should emulate it. /** * Returns the offset in the file where the transfer began. */ long getPosition(); /** * Returns the number of bytes to transfer. */ long getCount(); /** * Transfers the content of this file region to the specified channel. * * @param target the destination of the transfer * @param position the relative offset of the file where the transfer * begins from. For example, 0 will make the * transfer start from {@link #getPosition()}th byte and * {@link #getCount()} - 1 will make the last * byte of the region transferred. */ long transferTo(WritableByteChannel target, long position) throws IOException; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/FixedReceiveBufferSizePredictor.java000066400000000000000000000027701225554127700332630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * The {@link ReceiveBufferSizePredictor} that always yields the same buffer * size prediction. This predictor ignores the feed back from the I/O thread. */ public class FixedReceiveBufferSizePredictor implements ReceiveBufferSizePredictor { private final int bufferSize; /** * Creates a new predictor that always returns the same prediction of * the specified buffer size. */ public FixedReceiveBufferSizePredictor(int bufferSize) { if (bufferSize <= 0) { throw new IllegalArgumentException( "bufferSize must greater than 0: " + bufferSize); } this.bufferSize = bufferSize; } public int nextReceiveBufferSize() { return bufferSize; } public void previousReceiveBufferSize(int previousReceiveBufferSize) { // Ignore } } FixedReceiveBufferSizePredictorFactory.java000066400000000000000000000026061225554127700345320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * The {@link ReceiveBufferSizePredictorFactory} that returns a * {@link FixedReceiveBufferSizePredictor} with the pre-defined configuration. */ public class FixedReceiveBufferSizePredictorFactory implements ReceiveBufferSizePredictorFactory { private final ReceiveBufferSizePredictor predictor; /** * Creates a new factory that returns a {@link FixedReceiveBufferSizePredictor} * which always returns the same prediction of the specified buffer size. */ public FixedReceiveBufferSizePredictorFactory(int bufferSize) { predictor = new FixedReceiveBufferSizePredictor(bufferSize); } public ReceiveBufferSizePredictor getPredictor() throws Exception { return predictor; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/LifeCycleAwareChannelHandler.java000066400000000000000000000031261225554127700324620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelHandler} that is notified when it is added to or removed * from a {@link ChannelPipeline}. * *

Invalid access to the {@link ChannelHandlerContext}

* * Calling {@link ChannelHandlerContext#sendUpstream(ChannelEvent)} or * {@link ChannelHandlerContext#sendDownstream(ChannelEvent)} in * {@link #beforeAdd(ChannelHandlerContext)} or {@link #afterRemove(ChannelHandlerContext)} * might lead to an unexpected behavior. It is because the context object * might not have been fully added to the pipeline or the context object is not * a part of the pipeline anymore respectively. */ public interface LifeCycleAwareChannelHandler extends ChannelHandler { void beforeAdd(ChannelHandlerContext ctx) throws Exception; void afterAdd(ChannelHandlerContext ctx) throws Exception; void beforeRemove(ChannelHandlerContext ctx) throws Exception; void afterRemove(ChannelHandlerContext ctx) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/MessageEvent.java000066400000000000000000000025361225554127700274460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; /** * A {@link ChannelEvent} which represents the transmission or reception of a * message. It can mean the notification of a received message or the request * for writing a message, depending on whether it is an upstream event or a * downstream event respectively. Please refer to the {@link ChannelEvent} * documentation to find out what an upstream event and a downstream event are * and what fundamental differences they have. */ public interface MessageEvent extends ChannelEvent { /** * Returns the message. */ Object getMessage(); /** * Returns the remote address of the message. */ SocketAddress getRemoteAddress(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ReceiveBufferSizePredictor.java000066400000000000000000000037031225554127700323000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.buffer.ChannelBuffer; /** * Predicts the number of readable bytes in the receive buffer of a * {@link Channel}. *

* It calculates the close-to-optimal capacity of the {@link ChannelBuffer} * for the next read operation depending on the actual number of read bytes * in the previous read operation. More accurate the prediction is, more * effective the memory utilization will be. *

* Once a read operation is performed and the actual number of read bytes is * known, an I/O thread will call {@link #previousReceiveBufferSize(int)} to * update the predictor so it can predict more accurately next time. */ public interface ReceiveBufferSizePredictor { /** * Predicts the capacity of the {@link ChannelBuffer} for the next * read operation depending on the actual number of read bytes in the * previous read operation. * * @return the expected number of readable bytes this time */ int nextReceiveBufferSize(); /** * Updates this predictor by specifying the actual number of read bytes * in the previous read operation. * * @param previousReceiveBufferSize * the actual number of read bytes in the previous read operation */ void previousReceiveBufferSize(int previousReceiveBufferSize); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ReceiveBufferSizePredictorFactory.java000066400000000000000000000020041225554127700336210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * Creates a new {@link ReceiveBufferSizePredictor}. * * @apiviz.has org.jboss.netty.channel.ReceiveBufferSizePredictor oneway - - creates */ public interface ReceiveBufferSizePredictorFactory { /** * Returns a newly created {@link ReceiveBufferSizePredictor}. */ ReceiveBufferSizePredictor getPredictor() throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ServerChannel.java000066400000000000000000000017451225554127700276200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.channel.socket.ServerSocketChannel; /** * A {@link Channel} that accepts an incoming connection attempt and creates * its child {@link Channel}s by accepting them. {@link ServerSocketChannel} is * a good example. */ public interface ServerChannel extends Channel { // This is a tag interface. } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/ServerChannelFactory.java000066400000000000000000000016621225554127700311460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelFactory} that creates a {@link ServerChannel}. * * @apiviz.has org.jboss.netty.channel.ServerChannel oneway - - creates */ public interface ServerChannelFactory extends ChannelFactory { ServerChannel newChannel(ChannelPipeline pipeline); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/SimpleChannelDownstreamHandler.java000066400000000000000000000125301225554127700331370ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; /** * A {@link ChannelDownstreamHandler} which provides an individual handler * method for each event type. This handler down-casts the received downstream * event into more meaningful sub-type event and calls an appropriate handler * method with the down-cast event. The names of the methods starts with the * name of the operation and ends with {@code "Requested"} * (e.g. {@link #writeRequested(ChannelHandlerContext, MessageEvent) writeRequested}.) *

* Please use {@link SimpleChannelHandler} if you need to implement both * {@link ChannelUpstreamHandler} and {@link ChannelDownstreamHandler}. * *

Overriding the {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} method

*

* You can override the {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} * method just like overriding an ordinary Java method. Please make sure to * call {@code super.handleDownstream()} so that other handler methods are * invoked properly: *

*
public class MyChannelHandler extends {@link SimpleChannelDownstreamHandler} {
 *
 *     {@code @Override}
 *     public void handleDownstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *
 *         // Log all channel state changes.
 *         if (e instanceof {@link MessageEvent}) {
 *             logger.info("Writing:: " + e);
 *         }
 *
 *         super.handleDownstream(ctx, e);
 *     }
 * }
*

* Caution: *

* Use the *Later(..) methods of the {@link Channels} class if you want to send an upstream event * from a {@link ChannelDownstreamHandler} otherwise you may run into threading issues. * */ public class SimpleChannelDownstreamHandler implements ChannelDownstreamHandler { /** * {@inheritDoc} Down-casts the received downstream event into more * meaningful sub-type event and calls an appropriate handler method with * the down-casted event. */ public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof MessageEvent) { writeRequested(ctx, (MessageEvent) e); } else if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; switch (evt.getState()) { case OPEN: if (!Boolean.TRUE.equals(evt.getValue())) { closeRequested(ctx, evt); } break; case BOUND: if (evt.getValue() != null) { bindRequested(ctx, evt); } else { unbindRequested(ctx, evt); } break; case CONNECTED: if (evt.getValue() != null) { connectRequested(ctx, evt); } else { disconnectRequested(ctx, evt); } break; case INTEREST_OPS: setInterestOpsRequested(ctx, evt); break; default: ctx.sendDownstream(e); } } else { ctx.sendDownstream(e); } } /** * Invoked when {@link Channel#write(Object)} is called. */ public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#bind(SocketAddress)} was called. */ public void bindRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#connect(SocketAddress)} was called. */ public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#setInterestOps(int)} was called. */ public void setInterestOpsRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#disconnect()} was called. */ public void disconnectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#unbind()} was called. */ public void unbindRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#close()} was called. */ public void closeRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/SimpleChannelHandler.java000066400000000000000000000267041225554127700311030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import java.net.SocketAddress; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * A {@link ChannelHandler} which provides an individual handler method * for each event type. This handler down-casts the received upstream or * or downstream event into more meaningful sub-type event and calls an * appropriate handler method with the down-cast event. For an upstream * event, the names of the methods are identical to the upstream event names, * as introduced in the {@link ChannelEvent} documentation. For a * downstream event, the names of the methods starts with the name of the * operation and ends with {@code "Requested"} * (e.g. {@link #writeRequested(ChannelHandlerContext, MessageEvent) writeRequested}.) *

* Please use {@link SimpleChannelUpstreamHandler} or * {@link SimpleChannelDownstreamHandler} if you want to intercept only * upstream or downstream events. * *

Overriding the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} * and {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} method

*

* You can override the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} * and {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} * method just like overriding an ordinary Java method. Please make sure to * call {@code super.handleUpstream()} or {@code super.handleDownstream()} so * that other handler methods are invoked properly: *

*
public class MyChannelHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void handleUpstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *
 *         // Log all channel state changes.
 *         if (e instanceof {@link ChannelStateEvent}) {
 *             logger.info("Channel state changed: " + e);
 *         }
 *
 *         super.handleUpstream(ctx, e);
 *     }
 *
 *     {@code @Override}
 *     public void handleDownstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *
 *         // Log all channel state changes.
 *         if (e instanceof {@link MessageEvent}) {
 *             logger.info("Writing:: " + e);
 *         }
 *
 *         super.handleDownstream(ctx, e);
 *     }
 * }
*/ public class SimpleChannelHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SimpleChannelHandler.class.getName()); /** * {@inheritDoc} Down-casts the received upstream event into more * meaningful sub-type event and calls an appropriate handler method with * the down-casted event. */ public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof MessageEvent) { messageReceived(ctx, (MessageEvent) e); } else if (e instanceof WriteCompletionEvent) { WriteCompletionEvent evt = (WriteCompletionEvent) e; writeComplete(ctx, evt); } else if (e instanceof ChildChannelStateEvent) { ChildChannelStateEvent evt = (ChildChannelStateEvent) e; if (evt.getChildChannel().isOpen()) { childChannelOpen(ctx, evt); } else { childChannelClosed(ctx, evt); } } else if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; switch (evt.getState()) { case OPEN: if (Boolean.TRUE.equals(evt.getValue())) { channelOpen(ctx, evt); } else { channelClosed(ctx, evt); } break; case BOUND: if (evt.getValue() != null) { channelBound(ctx, evt); } else { channelUnbound(ctx, evt); } break; case CONNECTED: if (evt.getValue() != null) { channelConnected(ctx, evt); } else { channelDisconnected(ctx, evt); } break; case INTEREST_OPS: channelInterestChanged(ctx, evt); break; default: ctx.sendUpstream(e); } } else if (e instanceof ExceptionEvent) { exceptionCaught(ctx, (ExceptionEvent) e); } else { ctx.sendUpstream(e); } } /** * Invoked when a message object (e.g: {@link ChannelBuffer}) was received * from a remote peer. */ public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when an exception was raised by an I/O thread or a * {@link ChannelHandler}. */ public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (this == ctx.getPipeline().getLast()) { logger.warn( "EXCEPTION, please implement " + getClass().getName() + ".exceptionCaught() for proper handling.", e.getCause()); } ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} is open, but not bound nor connected. */ public void channelOpen( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} is open and bound to a local address, * but not connected. */ public void channelBound( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} is open, bound to a local address, and * connected to a remote address. */ public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel}'s {@link Channel#getInterestOps() interestOps} * was changed. */ public void channelInterestChanged( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} was disconnected from its remote peer. */ public void channelDisconnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} was unbound from the current local address. */ public void channelUnbound( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} was closed and all its related resources * were released. */ public void channelClosed( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when something was written into a {@link Channel}. */ public void writeComplete( ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a child {@link Channel} was open. * (e.g. a server channel accepted a connection) */ public void childChannelOpen( ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a child {@link Channel} was closed. * (e.g. the accepted connection was closed) */ public void childChannelClosed( ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * {@inheritDoc} Down-casts the received downstream event into more * meaningful sub-type event and calls an appropriate handler method with * the down-casted event. */ public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof MessageEvent) { writeRequested(ctx, (MessageEvent) e); } else if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; switch (evt.getState()) { case OPEN: if (!Boolean.TRUE.equals(evt.getValue())) { closeRequested(ctx, evt); } break; case BOUND: if (evt.getValue() != null) { bindRequested(ctx, evt); } else { unbindRequested(ctx, evt); } break; case CONNECTED: if (evt.getValue() != null) { connectRequested(ctx, evt); } else { disconnectRequested(ctx, evt); } break; case INTEREST_OPS: setInterestOpsRequested(ctx, evt); break; default: ctx.sendDownstream(e); } } else { ctx.sendDownstream(e); } } /** * Invoked when {@link Channel#write(Object)} is called. */ public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#bind(SocketAddress)} was called. */ public void bindRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#connect(SocketAddress)} was called. */ public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#setInterestOps(int)} was called. */ public void setInterestOpsRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#disconnect()} was called. */ public void disconnectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#unbind()} was called. */ public void unbindRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } /** * Invoked when {@link Channel#close()} was called. */ public void closeRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendDownstream(e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/SimpleChannelUpstreamHandler.java000066400000000000000000000220531225554127700326150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.util.List; /** * A {@link ChannelUpstreamHandler} which provides an individual handler method * for each event type. This handler down-casts the received upstream event * into more meaningful sub-type event and calls an appropriate handler method * with the down-cast event. The names of the methods are identical to the * upstream event names, as introduced in the {@link ChannelEvent} documentation. *

* Please use {@link SimpleChannelHandler} if you need to implement both * {@link ChannelUpstreamHandler} and {@link ChannelDownstreamHandler}. * *

Overriding the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} method

*

* You can override the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} * method just like overriding an ordinary Java method. Please make sure to * call {@code super.handleUpstream()} so that other handler methods are invoked * properly: *

*
public class MyChannelHandler extends {@link SimpleChannelUpstreamHandler} {
 *
 *     {@code @Override}
 *     public void handleUpstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
 *
 *         // Log all channel state changes.
 *         if (e instanceof {@link ChannelStateEvent}) {
 *             logger.info("Channel state changed: " + e);
 *         }
 *
 *         super.handleUpstream(ctx, e);
 *     }
 * }
*/ public class SimpleChannelUpstreamHandler implements ChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SimpleChannelUpstreamHandler.class.getName()); /** * {@inheritDoc} Down-casts the received upstream event into more * meaningful sub-type event and calls an appropriate handler method with * the down-casted event. */ public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof MessageEvent) { messageReceived(ctx, (MessageEvent) e); } else if (e instanceof WriteCompletionEvent) { WriteCompletionEvent evt = (WriteCompletionEvent) e; writeComplete(ctx, evt); } else if (e instanceof ChildChannelStateEvent) { ChildChannelStateEvent evt = (ChildChannelStateEvent) e; if (evt.getChildChannel().isOpen()) { childChannelOpen(ctx, evt); } else { childChannelClosed(ctx, evt); } } else if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; switch (evt.getState()) { case OPEN: if (Boolean.TRUE.equals(evt.getValue())) { channelOpen(ctx, evt); } else { channelClosed(ctx, evt); } break; case BOUND: if (evt.getValue() != null) { channelBound(ctx, evt); } else { channelUnbound(ctx, evt); } break; case CONNECTED: if (evt.getValue() != null) { channelConnected(ctx, evt); } else { channelDisconnected(ctx, evt); } break; case INTEREST_OPS: channelInterestChanged(ctx, evt); break; default: ctx.sendUpstream(e); } } else if (e instanceof ExceptionEvent) { exceptionCaught(ctx, (ExceptionEvent) e); } else { ctx.sendUpstream(e); } } /** * Invoked when a message object (e.g: {@link ChannelBuffer}) was received * from a remote peer. */ public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when an exception was raised by an I/O thread or a * {@link ChannelHandler}. */ public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { ChannelPipeline pipeline = ctx.getPipeline(); ChannelHandler last = pipeline.getLast(); if (!(last instanceof ChannelUpstreamHandler) && ctx instanceof DefaultChannelPipeline) { // The names comes in the order of which they are insert when using DefaultChannelPipeline List names = ctx.getPipeline().getNames(); for (int i = names.size() - 1; i >= 0; i--) { ChannelHandler handler = ctx.getPipeline().get(names.get(i)); if (handler instanceof ChannelUpstreamHandler) { // find the last handler last = handler; break; } } } if (this == last) { logger.warn( "EXCEPTION, please implement " + getClass().getName() + ".exceptionCaught() for proper handling.", e.getCause()); } ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} is open, but not bound nor connected. *
* * Be aware that this event is fired from within the Boss-Thread so you should not * execute any heavy operation in there as it will block the dispatching to other workers! */ public void channelOpen( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} is open and bound to a local address, * but not connected. *
* * Be aware that this event is fired from within the Boss-Thread so you should not * execute any heavy operation in there as it will block the dispatching to other workers! */ public void channelBound( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} is open, bound to a local address, and * connected to a remote address. *
* * Be aware that this event is fired from within the Boss-Thread so you should not * execute any heavy operation in there as it will block the dispatching to other workers! */ public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel}'s {@link Channel#getInterestOps() interestOps} * was changed. */ public void channelInterestChanged( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} was disconnected from its remote peer. */ public void channelDisconnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} was unbound from the current local address. */ public void channelUnbound( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a {@link Channel} was closed and all its related resources * were released. */ public void channelClosed( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when something was written into a {@link Channel}. */ public void writeComplete( ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a child {@link Channel} was open. * (e.g. a server channel accepted a connection) */ public void childChannelOpen( ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } /** * Invoked when a child {@link Channel} was closed. * (e.g. the accepted connection was closed) */ public void childChannelClosed( ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/StaticChannelPipeline.java000066400000000000000000000421741225554127700312700ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.ConversionUtil; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * A {@link ChannelPipeline} that might perform better at the cost of * disabled dynamic insertion and removal of {@link ChannelHandler}s. * An attempt to insert, remove, or replace a handler in this pipeline will * trigger an {@link UnsupportedOperationException}. * * @deprecated use {@link DefaultChannelPipeline} */ @Deprecated public class StaticChannelPipeline implements ChannelPipeline { // FIXME Code duplication with DefaultChannelPipeline static final InternalLogger logger = InternalLoggerFactory.getInstance(StaticChannelPipeline.class); private volatile Channel channel; private volatile ChannelSink sink; private final StaticChannelHandlerContext[] contexts; private final int lastIndex; private final Map name2ctx = new HashMap(4); /** * Creates a new pipeline from the specified handlers. * The names of the specified handlers are generated automatically; * the first handler's name is {@code "0"}, the second handler's name is * {@code "1"}, the third handler's name is {@code "2"}, and so on. */ public StaticChannelPipeline(ChannelHandler... handlers) { if (handlers == null) { throw new NullPointerException("handlers"); } if (handlers.length == 0) { throw new IllegalArgumentException("no handlers specified"); } // Get the number of first non-null handlers. StaticChannelHandlerContext[] contexts = new StaticChannelHandlerContext[handlers.length]; int nContexts; for (nContexts = 0; nContexts < contexts.length; nContexts ++) { ChannelHandler h = handlers[nContexts]; if (h == null) { break; } } if (nContexts == contexts.length) { this.contexts = contexts; lastIndex = contexts.length - 1; } else { this.contexts = contexts = new StaticChannelHandlerContext[nContexts]; lastIndex = nContexts - 1; } // Initialize the first non-null handlers only. for (int i = 0; i < nContexts; i ++) { ChannelHandler h = handlers[i]; String name = ConversionUtil.toString(i); StaticChannelHandlerContext ctx = new StaticChannelHandlerContext(i, name, h); contexts[i] = ctx; name2ctx.put(name, ctx); } for (ChannelHandlerContext ctx: contexts) { callBeforeAdd(ctx); callAfterAdd(ctx); } } public ChannelFuture execute(Runnable task) { return getSink().execute(this, task); } public Channel getChannel() { return channel; } public ChannelSink getSink() { ChannelSink sink = this.sink; if (sink == null) { return DefaultChannelPipeline.discardingSink; } return sink; } public void attach(Channel channel, ChannelSink sink) { if (channel == null) { throw new NullPointerException("channel"); } if (sink == null) { throw new NullPointerException("sink"); } if (this.channel != null || this.sink != null) { throw new IllegalStateException("attached already"); } this.channel = channel; this.sink = sink; } public boolean isAttached() { return sink != null; } public void addFirst(String name, ChannelHandler handler) { throw new UnsupportedOperationException(); } public void addLast(String name, ChannelHandler handler) { throw new UnsupportedOperationException(); } public void addBefore(String baseName, String name, ChannelHandler handler) { throw new UnsupportedOperationException(); } public void addAfter(String baseName, String name, ChannelHandler handler) { throw new UnsupportedOperationException(); } public void remove(ChannelHandler handler) { throw new UnsupportedOperationException(); } public ChannelHandler remove(String name) { throw new UnsupportedOperationException(); } public T remove(Class handlerType) { throw new UnsupportedOperationException(); } public ChannelHandler removeFirst() { throw new UnsupportedOperationException(); } public ChannelHandler removeLast() { throw new UnsupportedOperationException(); } public void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler) { throw new UnsupportedOperationException(); } public ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler) { throw new UnsupportedOperationException(); } public T replace( Class oldHandlerType, String newName, ChannelHandler newHandler) { throw new UnsupportedOperationException(); } private static void callBeforeAdd(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.beforeAdd(ctx); } catch (Throwable t) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".beforeAdd() has thrown an exception; not adding.", t); } } private static void callAfterAdd(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.afterAdd(ctx); } catch (Throwable t) { boolean removed = false; try { callBeforeRemove(ctx); callAfterRemove(ctx); removed = true; } catch (Throwable t2) { logger.warn("Failed to remove a handler: " + ctx.getName(), t2); } if (removed) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".afterAdd() has thrown an exception; removed.", t); } else { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".afterAdd() has thrown an exception; also failed to remove.", t); } } } private static void callBeforeRemove(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.beforeRemove(ctx); } catch (Throwable t) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".beforeRemove() has thrown an exception; not removing.", t); } } private static void callAfterRemove(ChannelHandlerContext ctx) { if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { return; } LifeCycleAwareChannelHandler h = (LifeCycleAwareChannelHandler) ctx.getHandler(); try { h.afterRemove(ctx); } catch (Throwable t) { throw new ChannelHandlerLifeCycleException( h.getClass().getName() + ".afterRemove() has thrown an exception.", t); } } public ChannelHandler getFirst() { return contexts[0].getHandler(); } public ChannelHandler getLast() { return contexts[contexts.length - 1].getHandler(); } public ChannelHandler get(String name) { StaticChannelHandlerContext ctx = name2ctx.get(name); if (ctx == null) { return null; } else { return ctx.getHandler(); } } public T get(Class handlerType) { ChannelHandlerContext ctx = getContext(handlerType); if (ctx == null) { return null; } else { @SuppressWarnings("unchecked") T handler = (T) ctx.getHandler(); return handler; } } public ChannelHandlerContext getContext(String name) { if (name == null) { throw new NullPointerException("name"); } return name2ctx.get(name); } public ChannelHandlerContext getContext(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } for (StaticChannelHandlerContext ctx: contexts) { if (ctx.getHandler() == handler) { return ctx; } } return null; } public ChannelHandlerContext getContext(Class handlerType) { if (handlerType == null) { throw new NullPointerException("handlerType"); } for (StaticChannelHandlerContext ctx: contexts) { if (handlerType.isAssignableFrom(ctx.getHandler().getClass())) { return ctx; } } return null; } public List getNames() { List list = new ArrayList(); for (StaticChannelHandlerContext ctx: contexts) { list.add(ctx.getName()); } return list; } public Map toMap() { Map map = new LinkedHashMap(); for (StaticChannelHandlerContext ctx: contexts) { map.put(ctx.getName(), ctx.getHandler()); } return map; } /** * Returns the {@link String} representation of this pipeline. */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append('{'); for (StaticChannelHandlerContext ctx: contexts) { buf.append('('); buf.append(ctx.getName()); buf.append(" = "); buf.append(ctx.getHandler().getClass().getName()); buf.append(')'); buf.append(", "); } buf.replace(buf.length() - 2, buf.length(), "}"); return buf.toString(); } public void sendUpstream(ChannelEvent e) { StaticChannelHandlerContext head = getActualUpstreamContext(0); if (head == null) { logger.warn( "The pipeline contains no upstream handlers; discarding: " + e); return; } sendUpstream(head, e); } void sendUpstream(StaticChannelHandlerContext ctx, ChannelEvent e) { try { ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e); } catch (Throwable t) { notifyHandlerException(e, t); } } public void sendDownstream(ChannelEvent e) { StaticChannelHandlerContext tail = getActualDownstreamContext(lastIndex); if (tail == null) { try { getSink().eventSunk(this, e); return; } catch (Throwable t) { notifyHandlerException(e, t); return; } } sendDownstream(tail, e); } void sendDownstream(StaticChannelHandlerContext ctx, ChannelEvent e) { if (e instanceof UpstreamMessageEvent) { throw new IllegalArgumentException("cannot send an upstream event to downstream"); } try { ((ChannelDownstreamHandler) ctx.getHandler()).handleDownstream(ctx, e); } catch (Throwable t) { // Unlike an upstream event, a downstream event usually has an // incomplete future which is supposed to be updated by ChannelSink. // However, if an exception is raised before the event reaches at // ChannelSink, the future is not going to be updated, so we update // here. e.getFuture().setFailure(t); notifyHandlerException(e, t); } } private StaticChannelHandlerContext getActualUpstreamContext(int index) { for (int i = index; i < contexts.length; i ++) { StaticChannelHandlerContext ctx = contexts[i]; if (ctx.canHandleUpstream()) { return ctx; } } return null; } private StaticChannelHandlerContext getActualDownstreamContext(int index) { for (int i = index; i >= 0; i --) { StaticChannelHandlerContext ctx = contexts[i]; if (ctx.canHandleDownstream()) { return ctx; } } return null; } protected void notifyHandlerException(ChannelEvent e, Throwable t) { if (e instanceof ExceptionEvent) { logger.warn( "An exception was thrown by a user handler " + "while handling an exception event (" + e + ')', t); return; } ChannelPipelineException pe; if (t instanceof ChannelPipelineException) { pe = (ChannelPipelineException) t; } else { pe = new ChannelPipelineException(t); } try { sink.exceptionCaught(this, e, pe); } catch (Exception e1) { logger.warn("An exception was thrown by an exception handler.", e1); } } private final class StaticChannelHandlerContext implements ChannelHandlerContext { private final int index; private final String name; private final ChannelHandler handler; private final boolean canHandleUpstream; private final boolean canHandleDownstream; private volatile Object attachment; StaticChannelHandlerContext( int index, String name, ChannelHandler handler) { if (name == null) { throw new NullPointerException("name"); } if (handler == null) { throw new NullPointerException("handler"); } canHandleUpstream = handler instanceof ChannelUpstreamHandler; canHandleDownstream = handler instanceof ChannelDownstreamHandler; if (!canHandleUpstream && !canHandleDownstream) { throw new IllegalArgumentException( "handler must be either " + ChannelUpstreamHandler.class.getName() + " or " + ChannelDownstreamHandler.class.getName() + '.'); } this.index = index; this.name = name; this.handler = handler; } public Channel getChannel() { return getPipeline().getChannel(); } public ChannelPipeline getPipeline() { return StaticChannelPipeline.this; } public boolean canHandleDownstream() { return canHandleDownstream; } public boolean canHandleUpstream() { return canHandleUpstream; } public ChannelHandler getHandler() { return handler; } public String getName() { return name; } public Object getAttachment() { return attachment; } public void setAttachment(Object attachment) { this.attachment = attachment; } public void sendDownstream(ChannelEvent e) { StaticChannelHandlerContext prev = getActualDownstreamContext(index - 1); if (prev == null) { try { getSink().eventSunk(StaticChannelPipeline.this, e); } catch (Throwable t) { notifyHandlerException(e, t); } } else { StaticChannelPipeline.this.sendDownstream(prev, e); } } public void sendUpstream(ChannelEvent e) { StaticChannelHandlerContext next = getActualUpstreamContext(index + 1); if (next != null) { StaticChannelPipeline.this.sendUpstream(next, e); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/SucceededChannelFuture.java000066400000000000000000000030051225554127700314200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * The {@link CompleteChannelFuture} which is succeeded already. It is * recommended to use {@link Channels#succeededFuture(Channel)} instead of * calling the constructor of this future. */ public class SucceededChannelFuture extends CompleteChannelFuture { /** * Creates a new instance. * * @param channel the {@link Channel} associated with this future */ public SucceededChannelFuture(Channel channel) { super(channel); } public Throwable getCause() { return null; } public boolean isSuccess() { return true; } @Deprecated public ChannelFuture rethrowIfFailed() throws Exception { return this; } public ChannelFuture sync() throws InterruptedException { return this; } public ChannelFuture syncUninterruptibly() { return this; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/UpstreamChannelStateEvent.java000066400000000000000000000054721225554127700321560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.jboss.netty.channel.Channels.*; /** * The default upstream {@link ChannelStateEvent} implementation. */ public class UpstreamChannelStateEvent implements ChannelStateEvent { private final Channel channel; private final ChannelState state; private final Object value; /** * Creates a new instance. */ public UpstreamChannelStateEvent( Channel channel, ChannelState state, Object value) { if (channel == null) { throw new NullPointerException("channel"); } if (state == null) { throw new NullPointerException("state"); } this.channel = channel; this.state = state; this.value = value; } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return succeededFuture(getChannel()); } public ChannelState getState() { return state; } public Object getValue() { return value; } @Override public String toString() { String channelString = getChannel().toString(); StringBuilder buf = new StringBuilder(channelString.length() + 64); buf.append(channelString); switch (getState()) { case OPEN: if (Boolean.TRUE.equals(getValue())) { buf.append(" OPEN"); } else { buf.append(" CLOSED"); } break; case BOUND: if (getValue() != null) { buf.append(" BOUND: "); buf.append(getValue()); } else { buf.append(" UNBOUND"); } break; case CONNECTED: if (getValue() != null) { buf.append(" CONNECTED: "); buf.append(getValue()); } else { buf.append(" DISCONNECTED"); } break; case INTEREST_OPS: buf.append(" INTEREST_CHANGED"); break; default: buf.append(getState().name()); buf.append(": "); buf.append(getValue()); } return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/UpstreamMessageEvent.java000066400000000000000000000045441225554127700311700ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.jboss.netty.channel.Channels.*; import java.net.SocketAddress; import org.jboss.netty.util.internal.StringUtil; /** * The default upstream {@link MessageEvent} implementation. */ public class UpstreamMessageEvent implements MessageEvent { private final Channel channel; private final Object message; private final SocketAddress remoteAddress; /** * Creates a new instance. */ public UpstreamMessageEvent( Channel channel, Object message, SocketAddress remoteAddress) { if (channel == null) { throw new NullPointerException("channel"); } if (message == null) { throw new NullPointerException("message"); } this.channel = channel; this.message = message; if (remoteAddress != null) { this.remoteAddress = remoteAddress; } else { this.remoteAddress = channel.getRemoteAddress(); } } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return succeededFuture(getChannel()); } public Object getMessage() { return message; } public SocketAddress getRemoteAddress() { return remoteAddress; } @Override public String toString() { if (getRemoteAddress() == getChannel().getRemoteAddress()) { return getChannel().toString() + " RECEIVED: " + StringUtil.stripControlCharacters(getMessage()); } else { return getChannel().toString() + " RECEIVED: " + StringUtil.stripControlCharacters(getMessage()) + " from " + getRemoteAddress(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/WriteCompletionEvent.java000066400000000000000000000023761225554127700312100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; /** * A {@link ChannelEvent} which represents the notification of the completion * of a write request on a {@link Channel}. This event is for going upstream * only. Please refer to the {@link ChannelEvent} documentation to find out * what an upstream event and a downstream event are and what fundamental * differences they have. */ public interface WriteCompletionEvent extends ChannelEvent { /** * Returns the amount of data written. * * @return the number of written bytes or messages, depending on the * type of the transport */ long getWrittenAmount(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/000077500000000000000000000000001225554127700253435ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/ChannelGroup.java000066400000000000000000000161621225554127700306010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.group; import java.net.SocketAddress; import java.util.Set; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ServerChannel; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.CharsetUtil; /** * A thread-safe {@link Set} that contains open {@link Channel}s and provides * various bulk operations on them. Using {@link ChannelGroup}, you can * categorize {@link Channel}s into a meaningful group (e.g. on a per-service * or per-state basis.) A closed {@link Channel} is automatically removed from * the collection, so that you don't need to worry about the life cycle of the * added {@link Channel}. A {@link Channel} can belong to more than one * {@link ChannelGroup}. * *

Broadcast a message to multiple {@link Channel}s

*

* If you need to broadcast a message to more than one {@link Channel}, you can * add the {@link Channel}s associated with the recipients and call {@link ChannelGroup#write(Object)}: *

 * {@link ChannelGroup} recipients = new {@link DefaultChannelGroup}();
 * recipients.add(channelA);
 * recipients.add(channelB);
 * ..
 * recipients.write({@link ChannelBuffers}.copiedBuffer(
 *         "Service will shut down for maintenance in 5 minutes.",
 *         {@link CharsetUtil}.UTF_8));
 * 
* *

Simplify shutdown process with {@link ChannelGroup}

*

* If both {@link ServerChannel}s and non-{@link ServerChannel}s exist in the * same {@link ChannelGroup}, any requested I/O operations on the group are * performed for the {@link ServerChannel}s first and then for the others. *

* This rule is very useful when you shut down a server in one shot: * *

 * {@link ChannelGroup} allChannels = new {@link DefaultChannelGroup}();
 *
 * public static void main(String[] args) throws Exception {
 *     {@link ServerBootstrap} b = new {@link ServerBootstrap}(..);
 *     ...
 *
 *     // Start the server
 *     b.getPipeline().addLast("handler", new MyHandler());
 *     {@link Channel} serverChannel = b.bind(..);
 *     allChannels.add(serverChannel);
 *
 *     ... Wait until the shutdown signal reception ...
 *
 *     // Close the serverChannel and then all accepted connections.
 *     allChannels.close().awaitUninterruptibly();
 *     b.releaseExternalResources();
 * }
 *
 * public class MyHandler extends {@link SimpleChannelUpstreamHandler} {
 *     {@code @Override}
 *     public void channelOpen({@link ChannelHandlerContext} ctx, {@link ChannelStateEvent} e) {
 *         // Add all open channels to the global group so that they are
 *         // closed on shutdown.
 *         allChannels.add(e.getChannel());
 *     }
 * }
 * 
* @apiviz.landmark * @apiviz.has org.jboss.netty.channel.group.ChannelGroupFuture oneway - - returns */ public interface ChannelGroup extends Set, Comparable { /** * Returns the name of this group. A group name is purely for helping * you to distinguish one group from others. */ String getName(); /** * Returns the {@link Channel} whose ID matches the specified integer. * * @return the matching {@link Channel} if found. {@code null} otherwise. */ Channel find(Integer id); /** * Calls {@link Channel#setInterestOps(int)} for all {@link Channel}s in * this group with the specified {@code interestOps}. Please note that * this operation is asynchronous as {@link Channel#setInterestOps(int)} is. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture setInterestOps(int interestOps); /** * Calls {@link Channel#setReadable(boolean)} for all {@link Channel}s in * this group with the specified boolean flag. Please note that this * operation is asynchronous as {@link Channel#setReadable(boolean)} is. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture setReadable(boolean readable); /** * Writes the specified {@code message} to all {@link Channel}s in this * group. If the specified {@code message} is an instance of * {@link ChannelBuffer}, it is automatically * {@linkplain ChannelBuffer#duplicate() duplicated} to avoid a race * condition. Please note that this operation is asynchronous as * {@link Channel#write(Object)} is. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture write(Object message); /** * Writes the specified {@code message} with the specified * {@code remoteAddress} to all {@link Channel}s in this group. If the * specified {@code message} is an instance of {@link ChannelBuffer}, it is * automatically {@linkplain ChannelBuffer#duplicate() duplicated} to avoid * a race condition. Please note that this operation is asynchronous as * {@link Channel#write(Object, SocketAddress)} is. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture write(Object message, SocketAddress remoteAddress); /** * Disconnects all {@link Channel}s in this group from their remote peers. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture disconnect(); /** * Unbinds all {@link Channel}s in this group from their local address. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture unbind(); /** * Closes all {@link Channel}s in this group. If the {@link Channel} is * connected to a remote peer or bound to a local address, it is * automatically disconnected and unbound. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ ChannelGroupFuture close(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/ChannelGroupFuture.java000066400000000000000000000235461225554127700320000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.group; import java.util.Iterator; import java.util.concurrent.TimeUnit; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.execution.ExecutionHandler; /** * The result of an asynchronous {@link ChannelGroup} operation. * {@link ChannelGroupFuture} is composed of {@link ChannelFuture}s which * represent the outcome of the individual I/O operations that affect the * {@link Channel}s in the {@link ChannelGroup}. * *

* All I/O operations in {@link ChannelGroup} are asynchronous. It means any * I/O calls will return immediately with no guarantee that the requested I/O * operations have been completed at the end of the call. Instead, you will be * returned with a {@link ChannelGroupFuture} instance which tells you when the * requested I/O operations have succeeded, failed, or cancelled. *

* Various methods are provided to let you check if the I/O operations has been * completed, wait for the completion, and retrieve the result of the I/O * operation. It also allows you to add more than one * {@link ChannelGroupFutureListener} so you can get notified when the I/O * operation have been completed. * *

Prefer {@link #addListener(ChannelGroupFutureListener)} to {@link #await()}

* * It is recommended to prefer {@link #addListener(ChannelGroupFutureListener)} to * {@link #await()} wherever possible to get notified when I/O operations are * done and to do any follow-up tasks. *

* {@link #addListener(ChannelGroupFutureListener)} is non-blocking. It simply * adds the specified {@link ChannelGroupFutureListener} to the * {@link ChannelGroupFuture}, and I/O thread will notify the listeners when * the I/O operations associated with the future is done. * {@link ChannelGroupFutureListener} yields the best performance and resource * utilization because it does not block at all, but it could be tricky to * implement a sequential logic if you are not used to event-driven programming. *

* By contrast, {@link #await()} is a blocking operation. Once called, the * caller thread blocks until all I/O operations are done. It is easier to * implement a sequential logic with {@link #await()}, but the caller thread * blocks unnecessarily until all I/O operations are done and there's relatively * expensive cost of inter-thread notification. Moreover, there's a chance of * dead lock in a particular circumstance, which is described below. * *

Do not call {@link #await()} inside {@link ChannelHandler}

*

* The event handler methods in {@link ChannelHandler} is often called by * an I/O thread unless an {@link ExecutionHandler} is in the * {@link ChannelPipeline}. If {@link #await()} is called by an event handler * method, which is called by the I/O thread, the I/O operation it is waiting * for might never be complete because {@link #await()} can block the I/O * operation it is waiting for, which is a dead lock. *

 * // BAD - NEVER DO THIS
 * {@code @Override}
 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     if (e.getMessage() instanceof ShutdownMessage) {
 *         {@link ChannelGroup} allChannels = MyServer.getAllChannels();
 *         {@link ChannelGroupFuture} future = allChannels.close();
 *         future.awaitUninterruptibly();
 *         // Perform post-shutdown operation
 *         // ...
 *     }
 * }
 *
 * // GOOD
 * {@code @Override}
 * public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
 *     if (e.getMessage() instanceof ShutdownMessage) {
 *         {@link ChannelGroup} allChannels = MyServer.getAllChannels();
 *         {@link ChannelGroupFuture} future = allChannels.close();
 *         future.addListener(new {@link ChannelGroupFutureListener}() {
 *             public void operationComplete({@link ChannelGroupFuture} future) {
 *                 // Perform post-closure operation
 *                 // ...
 *             }
 *         });
 *     }
 * }
 * 
*

* In spite of the disadvantages mentioned above, there are certainly the cases * where it is more convenient to call {@link #await()}. In such a case, please * make sure you do not call {@link #await()} in an I/O thread. Otherwise, * {@link IllegalStateException} will be raised to prevent a dead lock. * @apiviz.owns org.jboss.netty.channel.group.ChannelGroupFutureListener - - notifies */ public interface ChannelGroupFuture extends Iterable { /** * Returns the {@link ChannelGroup} which is associated with this future. */ ChannelGroup getGroup(); /** * Returns the {@link ChannelFuture} of the individual I/O operation which * is associated with the {@link Channel} whose ID matches the specified * integer. * * @return the matching {@link ChannelFuture} if found. * {@code null} otherwise. */ ChannelFuture find(Integer channelId); /** * Returns the {@link ChannelFuture} of the individual I/O operation which * is associated with the specified {@link Channel}. * * @return the matching {@link ChannelFuture} if found. * {@code null} otherwise. */ ChannelFuture find(Channel channel); /** * Returns {@code true} if and only if this future is * complete, regardless of whether the operation was successful, failed, * or canceled. */ boolean isDone(); /** * Returns {@code true} if and only if all I/O operations associated with * this future were successful without any failure. */ boolean isCompleteSuccess(); /** * Returns {@code true} if and only if the I/O operations associated with * this future were partially successful with some failure. */ boolean isPartialSuccess(); /** * Returns {@code true} if and only if all I/O operations associated with * this future have failed without any success. */ boolean isCompleteFailure(); /** * Returns {@code true} if and only if the I/O operations associated with * this future have failed partially with some success. */ boolean isPartialFailure(); /** * Adds the specified listener to this future. The * specified listener is notified when this future is * {@linkplain #isDone() done}. If this future is already * completed, the specified listener is notified immediately. */ void addListener(ChannelGroupFutureListener listener); /** * Removes the specified listener from this future. * The specified listener is no longer notified when this * future is {@linkplain #isDone() done}. If this * future is already completed, this method has no effect * and returns silently. */ void removeListener(ChannelGroupFutureListener listener); /** * Waits for this future to be completed. * * @throws InterruptedException * if the current thread was interrupted */ ChannelGroupFuture await() throws InterruptedException; /** * Waits for this future to be completed without * interruption. This method catches an {@link InterruptedException} and * discards it silently. */ ChannelGroupFuture awaitUninterruptibly(); /** * Waits for this future to be completed within the * specified time limit. * * @return {@code true} if and only if the future was completed within * the specified time limit * * @throws InterruptedException * if the current thread was interrupted */ boolean await(long timeout, TimeUnit unit) throws InterruptedException; /** * Waits for this future to be completed within the * specified time limit. * * @return {@code true} if and only if the future was completed within * the specified time limit * * @throws InterruptedException * if the current thread was interrupted */ boolean await(long timeoutMillis) throws InterruptedException; /** * Waits for this future to be completed within the * specified time limit without interruption. This method catches an * {@link InterruptedException} and discards it silently. * * @return {@code true} if and only if the future was completed within * the specified time limit */ boolean awaitUninterruptibly(long timeout, TimeUnit unit); /** * Waits for this future to be completed within the * specified time limit without interruption. This method catches an * {@link InterruptedException} and discards it silently. * * @return {@code true} if and only if the future was completed within * the specified time limit */ boolean awaitUninterruptibly(long timeoutMillis); /** * Returns the {@link Iterator} that enumerates all {@link ChannelFuture}s * which are associated with this future. Please note that the returned * {@link Iterator} is is unmodifiable, which means a {@link ChannelFuture} * cannot be removed from this future. */ Iterator iterator(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/ChannelGroupFutureListener.java000066400000000000000000000025641225554127700335030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.group; import java.util.EventListener; /** * Listens to the result of a {@link ChannelGroupFuture}. The result of the * asynchronous {@link ChannelGroup} I/O operations is notified once this * listener is added by calling {@link ChannelGroupFuture#addListener(ChannelGroupFutureListener)} * and all I/O operations are complete. */ public interface ChannelGroupFutureListener extends EventListener { /** * Invoked when all I/O operations associated with the * {@link ChannelGroupFuture} have been completed. * * @param future The source {@link ChannelGroupFuture} which called this * callback. */ void operationComplete(ChannelGroupFuture future) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/CombinedIterator.java000066400000000000000000000036601225554127700314450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.group; import java.util.Iterator; import java.util.NoSuchElementException; /** */ final class CombinedIterator implements Iterator { private final Iterator i1; private final Iterator i2; private Iterator currentIterator; CombinedIterator(Iterator i1, Iterator i2) { if (i1 == null) { throw new NullPointerException("i1"); } if (i2 == null) { throw new NullPointerException("i2"); } this.i1 = i1; this.i2 = i2; currentIterator = i1; } public boolean hasNext() { for (;;) { if (currentIterator.hasNext()) { return true; } if (currentIterator == i1) { currentIterator = i2; } else { return false; } } } public E next() { for (;;) { try { E e = currentIterator.next(); return e; } catch (NoSuchElementException e) { if (currentIterator == i1) { currentIterator = i2; } else { throw e; } } } } public void remove() { currentIterator.remove(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/DefaultChannelGroup.java000066400000000000000000000230731225554127700321050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.group; import java.net.SocketAddress; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ServerChannel; import org.jboss.netty.util.internal.ConcurrentHashMap; /** * The default {@link ChannelGroup} implementation. * @apiviz.landmark */ public class DefaultChannelGroup extends AbstractSet implements ChannelGroup { private static final AtomicInteger nextId = new AtomicInteger(); private final String name; private final ConcurrentMap serverChannels = new ConcurrentHashMap(); private final ConcurrentMap nonServerChannels = new ConcurrentHashMap(); private final ChannelFutureListener remover = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { remove(future.getChannel()); } }; /** * Creates a new group with a generated name. */ public DefaultChannelGroup() { this("group-0x" + Integer.toHexString(nextId.incrementAndGet())); } /** * Creates a new group with the specified {@code name}. Please note that * different groups can have the same name, which means no duplicate check * is done against group names. */ public DefaultChannelGroup(String name) { if (name == null) { throw new NullPointerException("name"); } this.name = name; } public String getName() { return name; } @Override public boolean isEmpty() { return nonServerChannels.isEmpty() && serverChannels.isEmpty(); } @Override public int size() { return nonServerChannels.size() + serverChannels.size(); } public Channel find(Integer id) { Channel c = nonServerChannels.get(id); if (c != null) { return c; } else { return serverChannels.get(id); } } @Override public boolean contains(Object o) { if (o instanceof Integer) { return nonServerChannels.containsKey(o) || serverChannels.containsKey(o); } else if (o instanceof Channel) { Channel c = (Channel) o; if (o instanceof ServerChannel) { return serverChannels.containsKey(c.getId()); } else { return nonServerChannels.containsKey(c.getId()); } } else { return false; } } @Override public boolean add(Channel channel) { ConcurrentMap map = channel instanceof ServerChannel? serverChannels : nonServerChannels; boolean added = map.putIfAbsent(channel.getId(), channel) == null; if (added) { channel.getCloseFuture().addListener(remover); } return added; } @Override public boolean remove(Object o) { Channel c = null; if (o instanceof Integer) { c = nonServerChannels.remove(o); if (c == null) { c = serverChannels.remove(o); } } else if (o instanceof Channel) { c = (Channel) o; if (c instanceof ServerChannel) { c = serverChannels.remove(c.getId()); } else { c = nonServerChannels.remove(c.getId()); } } if (c == null) { return false; } c.getCloseFuture().removeListener(remover); return true; } @Override public void clear() { nonServerChannels.clear(); serverChannels.clear(); } @Override public Iterator iterator() { return new CombinedIterator( serverChannels.values().iterator(), nonServerChannels.values().iterator()); } @Override public Object[] toArray() { Collection channels = new ArrayList(size()); channels.addAll(serverChannels.values()); channels.addAll(nonServerChannels.values()); return channels.toArray(); } @Override public T[] toArray(T[] a) { Collection channels = new ArrayList(size()); channels.addAll(serverChannels.values()); channels.addAll(nonServerChannels.values()); return channels.toArray(a); } public ChannelGroupFuture close() { Map futures = new LinkedHashMap(size()); for (Channel c: serverChannels.values()) { futures.put(c.getId(), c.close().awaitUninterruptibly()); } for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.close()); } return new DefaultChannelGroupFuture(this, futures); } public ChannelGroupFuture disconnect() { Map futures = new LinkedHashMap(size()); for (Channel c: serverChannels.values()) { futures.put(c.getId(), c.disconnect().awaitUninterruptibly()); } for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.disconnect()); } return new DefaultChannelGroupFuture(this, futures); } public ChannelGroupFuture setInterestOps(int interestOps) { Map futures = new LinkedHashMap(size()); for (Channel c: serverChannels.values()) { futures.put(c.getId(), c.setInterestOps(interestOps).awaitUninterruptibly()); } for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.setInterestOps(interestOps)); } return new DefaultChannelGroupFuture(this, futures); } public ChannelGroupFuture setReadable(boolean readable) { Map futures = new LinkedHashMap(size()); for (Channel c: serverChannels.values()) { futures.put(c.getId(), c.setReadable(readable).awaitUninterruptibly()); } for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.setReadable(readable)); } return new DefaultChannelGroupFuture(this, futures); } public ChannelGroupFuture unbind() { Map futures = new LinkedHashMap(size()); for (Channel c: serverChannels.values()) { futures.put(c.getId(), c.unbind().awaitUninterruptibly()); } for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.unbind()); } return new DefaultChannelGroupFuture(this, futures); } public ChannelGroupFuture write(Object message) { Map futures = new LinkedHashMap(size()); if (message instanceof ChannelBuffer) { ChannelBuffer buf = (ChannelBuffer) message; for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.write(buf.duplicate())); } } else { for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.write(message)); } } return new DefaultChannelGroupFuture(this, futures); } public ChannelGroupFuture write(Object message, SocketAddress remoteAddress) { Map futures = new LinkedHashMap(size()); if (message instanceof ChannelBuffer) { ChannelBuffer buf = (ChannelBuffer) message; for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.write(buf.duplicate(), remoteAddress)); } } else { for (Channel c: nonServerChannels.values()) { futures.put(c.getId(), c.write(message, remoteAddress)); } } return new DefaultChannelGroupFuture(this, futures); } @Override public int hashCode() { return System.identityHashCode(this); } @Override public boolean equals(Object o) { return this == o; } public int compareTo(ChannelGroup o) { int v = getName().compareTo(o.getName()); if (v != 0) { return v; } return System.identityHashCode(this) - System.identityHashCode(o); } @Override public String toString() { return getClass().getSimpleName() + "(name: " + getName() + ", size: " + size() + ')'; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/DefaultChannelGroupFuture.java000066400000000000000000000262271225554127700333040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.group; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.DeadLockProofWorker; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import static java.util.concurrent.TimeUnit.*; /** * The default {@link ChannelGroupFuture} implementation. */ public class DefaultChannelGroupFuture implements ChannelGroupFuture { private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelGroupFuture.class); private final ChannelGroup group; final Map futures; private ChannelGroupFutureListener firstListener; private List otherListeners; private boolean done; int successCount; int failureCount; private int waiters; private final ChannelFutureListener childListener = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { boolean success = future.isSuccess(); boolean callSetDone; synchronized (DefaultChannelGroupFuture.this) { if (success) { successCount ++; } else { failureCount ++; } callSetDone = successCount + failureCount == futures.size(); assert successCount + failureCount <= futures.size(); } if (callSetDone) { setDone(); } } }; /** * Creates a new instance. */ public DefaultChannelGroupFuture(ChannelGroup group, Collection futures) { if (group == null) { throw new NullPointerException("group"); } if (futures == null) { throw new NullPointerException("futures"); } this.group = group; Map futureMap = new LinkedHashMap(); for (ChannelFuture f: futures) { futureMap.put(f.getChannel().getId(), f); } this.futures = Collections.unmodifiableMap(futureMap); for (ChannelFuture f: this.futures.values()) { f.addListener(childListener); } // Done on arrival? if (this.futures.isEmpty()) { setDone(); } } DefaultChannelGroupFuture(ChannelGroup group, Map futures) { this.group = group; this.futures = Collections.unmodifiableMap(futures); for (ChannelFuture f: this.futures.values()) { f.addListener(childListener); } // Done on arrival? if (this.futures.isEmpty()) { setDone(); } } public ChannelGroup getGroup() { return group; } public ChannelFuture find(Integer channelId) { return futures.get(channelId); } public ChannelFuture find(Channel channel) { return futures.get(channel.getId()); } public Iterator iterator() { return futures.values().iterator(); } public synchronized boolean isDone() { return done; } public synchronized boolean isCompleteSuccess() { return successCount == futures.size(); } public synchronized boolean isPartialSuccess() { return successCount != 0 && successCount != futures.size(); } public synchronized boolean isPartialFailure() { return failureCount != 0 && failureCount != futures.size(); } public synchronized boolean isCompleteFailure() { int futureCnt = futures.size(); return futureCnt != 0 && failureCount == futureCnt; } public void addListener(ChannelGroupFutureListener listener) { if (listener == null) { throw new NullPointerException("listener"); } boolean notifyNow = false; synchronized (this) { if (done) { notifyNow = true; } else { if (firstListener == null) { firstListener = listener; } else { if (otherListeners == null) { otherListeners = new ArrayList(1); } otherListeners.add(listener); } } } if (notifyNow) { notifyListener(listener); } } public void removeListener(ChannelGroupFutureListener listener) { if (listener == null) { throw new NullPointerException("listener"); } synchronized (this) { if (!done) { if (listener == firstListener) { if (otherListeners != null && !otherListeners.isEmpty()) { firstListener = otherListeners.remove(0); } else { firstListener = null; } } else if (otherListeners != null) { otherListeners.remove(listener); } } } } public ChannelGroupFuture await() throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } synchronized (this) { while (!done) { checkDeadLock(); waiters++; try { wait(); } finally { waiters--; } } } return this; } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return await0(unit.toNanos(timeout), true); } public boolean await(long timeoutMillis) throws InterruptedException { return await0(MILLISECONDS.toNanos(timeoutMillis), true); } public ChannelGroupFuture awaitUninterruptibly() { boolean interrupted = false; synchronized (this) { while (!done) { checkDeadLock(); waiters++; try { wait(); } catch (InterruptedException e) { interrupted = true; } finally { waiters--; } } } if (interrupted) { Thread.currentThread().interrupt(); } return this; } public boolean awaitUninterruptibly(long timeout, TimeUnit unit) { try { return await0(unit.toNanos(timeout), false); } catch (InterruptedException e) { throw new InternalError(); } } public boolean awaitUninterruptibly(long timeoutMillis) { try { return await0(MILLISECONDS.toNanos(timeoutMillis), false); } catch (InterruptedException e) { throw new InternalError(); } } private boolean await0(long timeoutNanos, boolean interruptable) throws InterruptedException { if (interruptable && Thread.interrupted()) { throw new InterruptedException(); } long startTime = timeoutNanos <= 0 ? 0 : System.nanoTime(); long waitTime = timeoutNanos; boolean interrupted = false; try { synchronized (this) { if (done || waitTime <= 0) { return done; } checkDeadLock(); waiters++; try { for (;;) { try { wait(waitTime / 1000000, (int) (waitTime % 1000000)); } catch (InterruptedException e) { if (interruptable) { throw e; } else { interrupted = true; } } if (done) { return true; } else { waitTime = timeoutNanos - (System.nanoTime() - startTime); if (waitTime <= 0) { return done; } } } } finally { waiters--; } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } private static void checkDeadLock() { if (DeadLockProofWorker.PARENT.get() != null) { throw new IllegalStateException( "await*() in I/O thread causes a dead lock or " + "sudden performance drop. Use addListener() instead or " + "call await*() from a different thread."); } } boolean setDone() { synchronized (this) { // Allow only once. if (done) { return false; } done = true; if (waiters > 0) { notifyAll(); } } notifyListeners(); return true; } private void notifyListeners() { // This method doesn't need synchronization because: // 1) This method is always called after synchronized (this) block. // Hence any listener list modification happens-before this method. // 2) This method is called only when 'done' is true. Once 'done' // becomes true, the listener list is never modified - see add/removeListener() if (firstListener != null) { notifyListener(firstListener); firstListener = null; if (otherListeners != null) { for (ChannelGroupFutureListener l: otherListeners) { notifyListener(l); } otherListeners = null; } } } private void notifyListener(ChannelGroupFutureListener l) { try { l.operationComplete(this); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn( "An exception was thrown by " + ChannelFutureListener.class.getSimpleName() + '.', t); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/group/package-info.java000066400000000000000000000016131225554127700305330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * A channel registry which helps a user maintain the list of open * {@link org.jboss.netty.channel.Channel}s and perform bulk operations on them. * * @apiviz.exclude ^java * @apiviz.exclude \.DefaultChannelGroupFuture$ */ package org.jboss.netty.channel.group; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/000077500000000000000000000000001225554127700253015ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/DefaultLocalChannel.java000066400000000000000000000152421225554127700320000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import static org.jboss.netty.channel.Channels.*; import java.nio.channels.ClosedChannelException; import java.nio.channels.NotYetConnectedException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.netty.channel.AbstractChannel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.DefaultChannelConfig; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.util.internal.ThreadLocalBoolean; /** */ final class DefaultLocalChannel extends AbstractChannel implements LocalChannel { // TODO Move the state management up to AbstractChannel to remove duplication. private static final int ST_OPEN = 0; private static final int ST_BOUND = 1; private static final int ST_CONNECTED = 2; private static final int ST_CLOSED = -1; final AtomicInteger state = new AtomicInteger(ST_OPEN); private final ChannelConfig config; private final ThreadLocalBoolean delivering = new ThreadLocalBoolean(); final Queue writeBuffer = new ConcurrentLinkedQueue(); volatile DefaultLocalChannel pairedChannel; volatile LocalAddress localAddress; volatile LocalAddress remoteAddress; DefaultLocalChannel( LocalServerChannel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, DefaultLocalChannel pairedChannel) { super(parent, factory, pipeline, sink); this.pairedChannel = pairedChannel; config = new DefaultChannelConfig(); // TODO Move the state variable to AbstractChannel so that we don't need // to add many listeners. getCloseFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { state.set(ST_CLOSED); } }); fireChannelOpen(this); } public ChannelConfig getConfig() { return config; } @Override public boolean isOpen() { return state.get() >= ST_OPEN; } public boolean isBound() { return state.get() >= ST_BOUND; } public boolean isConnected() { return state.get() == ST_CONNECTED; } void setBound() throws ClosedChannelException { if (!state.compareAndSet(ST_OPEN, ST_BOUND)) { switch (state.get()) { case ST_CLOSED: throw new ClosedChannelException(); default: throw new ChannelException("already bound"); } } } void setConnected() { if (state.get() != ST_CLOSED) { state.set(ST_CONNECTED); } } @Override protected boolean setClosed() { return super.setClosed(); } public LocalAddress getLocalAddress() { return localAddress; } public LocalAddress getRemoteAddress() { return remoteAddress; } void closeNow(ChannelFuture future) { LocalAddress localAddress = this.localAddress; try { // Close the self. if (!setClosed()) { return; } DefaultLocalChannel pairedChannel = this.pairedChannel; if (pairedChannel != null) { this.pairedChannel = null; fireChannelDisconnected(this); fireChannelUnbound(this); } fireChannelClosed(this); // Close the peer. if (pairedChannel == null || !pairedChannel.setClosed()) { return; } DefaultLocalChannel me = pairedChannel.pairedChannel; if (me != null) { pairedChannel.pairedChannel = null; fireChannelDisconnected(pairedChannel); fireChannelUnbound(pairedChannel); } fireChannelClosed(pairedChannel); } finally { future.setSuccess(); if (localAddress != null && getParent() == null) { LocalChannelRegistry.unregister(localAddress); } } } void flushWriteBuffer() { DefaultLocalChannel pairedChannel = this.pairedChannel; if (pairedChannel != null) { if (pairedChannel.isConnected()) { // Channel is open and connected and channelConnected event has // been fired. if (!delivering.get()) { delivering.set(true); try { for (;;) { MessageEvent e = writeBuffer.poll(); if (e == null) { break; } fireMessageReceived(pairedChannel, e.getMessage()); e.getFuture().setSuccess(); fireWriteComplete(this, 1); } } finally { delivering.set(false); } } } else { // Channel is open and connected but channelConnected event has // not been fired yet. } } else { // Channel is closed or not connected yet - notify as failures. Exception cause; if (isOpen()) { cause = new NotYetConnectedException(); } else { cause = new ClosedChannelException(); } for (;;) { MessageEvent e = writeBuffer.poll(); if (e == null) { break; } e.getFuture().setFailure(cause); fireExceptionCaught(this, cause); } } } } DefaultLocalClientChannelFactory.java000066400000000000000000000030051225554127700344020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; /** * The default {@link LocalClientChannelFactory} implementation. * @apiviz.landmark */ public class DefaultLocalClientChannelFactory implements LocalClientChannelFactory { private final ChannelSink sink; /** * Creates a new instance. */ public DefaultLocalClientChannelFactory() { sink = new LocalClientChannelSink(); } public LocalChannel newChannel(ChannelPipeline pipeline) { return new DefaultLocalChannel(null, this, pipeline, sink, null); } /** * Does nothing because this implementation does not require any external * resources. */ public void releaseExternalResources() { // No external resources. } public void shutdown() { // nothing to shutdown } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/DefaultLocalServerChannel.java000066400000000000000000000037311225554127700331670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import static org.jboss.netty.channel.Channels.*; import java.util.concurrent.atomic.AtomicBoolean; import org.jboss.netty.channel.AbstractServerChannel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.DefaultServerChannelConfig; /** */ final class DefaultLocalServerChannel extends AbstractServerChannel implements LocalServerChannel { final ChannelConfig channelConfig; final AtomicBoolean bound = new AtomicBoolean(); volatile LocalAddress localAddress; DefaultLocalServerChannel(ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(factory, pipeline, sink); channelConfig = new DefaultServerChannelConfig(); fireChannelOpen(this); } public ChannelConfig getConfig() { return channelConfig; } public boolean isBound() { return isOpen() && bound.get(); } public LocalAddress getLocalAddress() { return isBound()? localAddress : null; } public LocalAddress getRemoteAddress() { return null; } @Override protected boolean setClosed() { return super.setClosed(); } } DefaultLocalServerChannelFactory.java000066400000000000000000000032461225554127700344410ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.group.DefaultChannelGroup; /** * The default {@link LocalServerChannelFactory} implementation. * @apiviz.landmark */ public class DefaultLocalServerChannelFactory implements LocalServerChannelFactory { private final DefaultChannelGroup group = new DefaultChannelGroup(); private final ChannelSink sink = new LocalServerChannelSink(); public LocalServerChannel newChannel(ChannelPipeline pipeline) { LocalServerChannel channel = new DefaultLocalServerChannel(this, pipeline, sink); group.add(channel); return channel; } /** * Release all the previous created channels. * This takes care of calling {@link LocalChannelRegistry#unregister(LocalAddress)} for each of them. */ public void releaseExternalResources() { group.close().awaitUninterruptibly(); } public void shutdown() { // nothing to shutdown } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalAddress.java000066400000000000000000000075051225554127700305130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import java.net.SocketAddress; /** * An endpoint in the local transport. Each endpoint is identified by a unique * case-insensitive string, except for the pre-defined value called * {@code "ephemeral"}. * *

Ephemeral Address

* * An ephemeral address is an anonymous address which is assigned temporarily * and is released as soon as the connection is closed. All ephemeral addresses * have the same ID, {@code "ephemeral"}, but they are not equal to each other. * @apiviz.landmark */ public final class LocalAddress extends SocketAddress implements Comparable { private static final long serialVersionUID = -3601961747680808645L; public static final String EPHEMERAL = "ephemeral"; private final String id; private final boolean ephemeral; /** * Creates a new instance with the specified ID. */ public LocalAddress(int id) { this(String.valueOf(id)); } /** * Creates a new instance with the specified ID. */ public LocalAddress(String id) { if (id == null) { throw new NullPointerException("id"); } id = id.trim().toLowerCase(); if (id.length() == 0) { throw new IllegalArgumentException("empty id"); } this.id = id; ephemeral = "ephemeral".equals(id); } /** * Returns the ID of this address. */ public String getId() { return id; } /** * Returns {@code true} if and only if this address is ephemeral. */ public boolean isEphemeral() { return ephemeral; } @Override public int hashCode() { if (ephemeral) { return System.identityHashCode(this); } else { return id.hashCode(); } } @Override public boolean equals(Object o) { if (!(o instanceof LocalAddress)) { return false; } if (ephemeral) { return this == o; } else { return getId().equals(((LocalAddress) o).getId()); } } // FIXME: This comparison is broken! Assign distinct port numbers for // ephemeral ports, just like O/S does for port number 0. It will // break backward compatibility though. public int compareTo(LocalAddress o) { if (ephemeral) { if (o.ephemeral) { if (this == o) { return 0; } int a = System.identityHashCode(this); int b = System.identityHashCode(o); if (a < b) { return -1; } else if (a > b) { return 1; } else { throw new Error( "Two different ephemeral addresses have " + "same identityHashCode."); } } else { return 1; } } else { if (o.ephemeral) { return -1; } else { return getId().compareTo(o.getId()); } } } @Override public String toString() { return "local:" + getId(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalChannel.java000066400000000000000000000015751225554127700304770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.Channel; /** * A {@link Channel} for the local transport. */ public interface LocalChannel extends Channel { LocalAddress getLocalAddress(); LocalAddress getRemoteAddress(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalChannelRegistry.java000066400000000000000000000027151225554127700322250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import java.util.concurrent.ConcurrentMap; import org.jboss.netty.channel.Channel; import org.jboss.netty.util.internal.ConcurrentHashMap; /** */ final class LocalChannelRegistry { private static final ConcurrentMap map = new ConcurrentHashMap(); static boolean isRegistered(LocalAddress address) { return map.containsKey(address); } static Channel getChannel(LocalAddress address) { return map.get(address); } static boolean register(LocalAddress address, Channel channel) { return map.putIfAbsent(address, channel) == null; } static boolean unregister(LocalAddress address) { return map.remove(address) != null; } private LocalChannelRegistry() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalClientChannelFactory.java000066400000000000000000000017251225554127700331630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; /** * A {@link ChannelFactory} that creates a client-side {@link LocalChannel}. */ public interface LocalClientChannelFactory extends ChannelFactory { LocalChannel newChannel(ChannelPipeline pipeline); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalClientChannelSink.java000066400000000000000000000134261225554127700324610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.AbstractChannelSink; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.io.IOException; import java.net.ConnectException; import static org.jboss.netty.channel.Channels.*; /** */ final class LocalClientChannelSink extends AbstractChannelSink { private static final InternalLogger logger = InternalLoggerFactory.getInstance(LocalClientChannelSink.class); public void eventSunk(ChannelPipeline pipeline, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { ChannelStateEvent event = (ChannelStateEvent) e; DefaultLocalChannel channel = (DefaultLocalChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { channel.closeNow(future); } break; case BOUND: if (value != null) { bind(channel, future, (LocalAddress) value); } else { channel.closeNow(future); } break; case CONNECTED: if (value != null) { connect(channel, future, (LocalAddress) value); } else { channel.closeNow(future); } break; case INTEREST_OPS: // Unsupported - discard silently. future.setSuccess(); break; } } else if (e instanceof MessageEvent) { MessageEvent event = (MessageEvent) e; DefaultLocalChannel channel = (DefaultLocalChannel) event.getChannel(); boolean offered = channel.writeBuffer.offer(event); assert offered; channel.flushWriteBuffer(); } } private static void bind(DefaultLocalChannel channel, ChannelFuture future, LocalAddress localAddress) { try { if (!LocalChannelRegistry.register(localAddress, channel)) { throw new ChannelException("address already in use: " + localAddress); } channel.setBound(); channel.localAddress = localAddress; future.setSuccess(); fireChannelBound(channel, localAddress); } catch (Throwable t) { LocalChannelRegistry.unregister(localAddress); future.setFailure(t); fireExceptionCaught(channel, t); } } private void connect(DefaultLocalChannel channel, ChannelFuture future, LocalAddress remoteAddress) { Channel remoteChannel = LocalChannelRegistry.getChannel(remoteAddress); if (!(remoteChannel instanceof DefaultLocalServerChannel)) { future.setFailure(new ConnectException( "connection refused: " + remoteAddress)); return; } DefaultLocalServerChannel serverChannel = (DefaultLocalServerChannel) remoteChannel; ChannelPipeline pipeline; try { pipeline = serverChannel.getConfig().getPipelineFactory().getPipeline(); } catch (Exception e) { future.setFailure(e); fireExceptionCaught(channel, e); if (logger.isWarnEnabled()) { logger.warn( "Failed to initialize an accepted socket.", e); } return; } future.setSuccess(); DefaultLocalChannel acceptedChannel = new DefaultLocalChannel( serverChannel, serverChannel.getFactory(), pipeline, this, channel); channel.pairedChannel = acceptedChannel; // check if the channel was bound before. See #276 if (!channel.isBound()) { bind(channel, succeededFuture(channel), new LocalAddress(LocalAddress.EPHEMERAL)); } channel.remoteAddress = serverChannel.getLocalAddress(); channel.setConnected(); fireChannelConnected(channel, serverChannel.getLocalAddress()); acceptedChannel.localAddress = serverChannel.getLocalAddress(); try { acceptedChannel.setBound(); } catch (IOException e) { throw new Error(e); } fireChannelBound(acceptedChannel, channel.getRemoteAddress()); acceptedChannel.remoteAddress = channel.getLocalAddress(); acceptedChannel.setConnected(); fireChannelConnected(acceptedChannel, channel.getLocalAddress()); // Flush something that was written in channelBound / channelConnected channel.flushWriteBuffer(); acceptedChannel.flushWriteBuffer(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalServerChannel.java000066400000000000000000000016251225554127700316620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.ServerChannel; /** * A {@link ServerChannel} for the local transport. */ public interface LocalServerChannel extends ServerChannel { LocalAddress getLocalAddress(); LocalAddress getRemoteAddress(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalServerChannelFactory.java000066400000000000000000000017471225554127700332170ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ServerChannelFactory; /** * A {@link ServerChannelFactory} that creates a {@link LocalServerChannel}. */ public interface LocalServerChannelFactory extends ServerChannelFactory { LocalServerChannel newChannel(ChannelPipeline pipeline); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/LocalServerChannelSink.java000066400000000000000000000120311225554127700325000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.AbstractChannelSink; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; final class LocalServerChannelSink extends AbstractChannelSink { public void eventSunk(ChannelPipeline pipeline, ChannelEvent e) throws Exception { Channel channel = e.getChannel(); if (channel instanceof DefaultLocalServerChannel) { handleServerChannel(e); } else if (channel instanceof DefaultLocalChannel) { handleAcceptedChannel(e); } } private static void handleServerChannel(ChannelEvent e) { if (!(e instanceof ChannelStateEvent)) { return; } ChannelStateEvent event = (ChannelStateEvent) e; DefaultLocalServerChannel channel = (DefaultLocalServerChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { close(channel, future); } break; case BOUND: if (value != null) { bind(channel, future, (LocalAddress) value); } else { close(channel, future); } break; } } private static void handleAcceptedChannel(ChannelEvent e) { if (e instanceof ChannelStateEvent) { ChannelStateEvent event = (ChannelStateEvent) e; DefaultLocalChannel channel = (DefaultLocalChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { channel.closeNow(future); } break; case BOUND: case CONNECTED: if (value == null) { channel.closeNow(future); } break; case INTEREST_OPS: // Unsupported - discard silently. future.setSuccess(); break; } } else if (e instanceof MessageEvent) { MessageEvent event = (MessageEvent) e; DefaultLocalChannel channel = (DefaultLocalChannel) event.getChannel(); boolean offered = channel.writeBuffer.offer(event); assert offered; channel.flushWriteBuffer(); } } private static void bind(DefaultLocalServerChannel channel, ChannelFuture future, LocalAddress localAddress) { try { if (!LocalChannelRegistry.register(localAddress, channel)) { throw new ChannelException("address already in use: " + localAddress); } if (!channel.bound.compareAndSet(false, true)) { throw new ChannelException("already bound"); } channel.localAddress = localAddress; future.setSuccess(); fireChannelBound(channel, localAddress); } catch (Throwable t) { LocalChannelRegistry.unregister(localAddress); future.setFailure(t); fireExceptionCaught(channel, t); } } private static void close(DefaultLocalServerChannel channel, ChannelFuture future) { try { if (channel.setClosed()) { future.setSuccess(); LocalAddress localAddress = channel.localAddress; if (channel.bound.compareAndSet(true, false)) { channel.localAddress = null; LocalChannelRegistry.unregister(localAddress); fireChannelUnbound(channel); } fireChannelClosed(channel); } else { future.setSuccess(); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/local/package-info.java000066400000000000000000000015311225554127700304700ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * A virtual transport that enables the communication between the two * parties in the same virtual machine. * * @apiviz.exclude ^java\.lang\. * @apiviz.exclude Channel$ */ package org.jboss.netty.channel.local; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/package-info.java000066400000000000000000000026341225554127700274030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * The core channel API which is asynchronous and event-driven abstraction of * various transports such as a * NIO Channel. * * @apiviz.landmark * @apiviz.exclude ^java * @apiviz.exclude ^org\.jboss\.netty\.channel\.[^\.]+\. * @apiviz.exclude ^org\.jboss\.netty\.(bootstrap|handler|util)\. * @apiviz.exclude \.(Abstract|Default|Static).*$ * @apiviz.exclude \.(Downstream|Upstream).*Event$ * @apiviz.exclude \.[A-Za-z]+ChannelFuture$ * @apiviz.exclude \.ChannelPipelineFactory$ * @apiviz.exclude \.ChannelHandlerContext$ * @apiviz.exclude \.ChannelSink$ * @apiviz.exclude \.ChannelLocal$ * @apiviz.exclude \.[^\.]+ReceiveBufferSizePredictor(Factory)?$ * @apiviz.exclude \.FileRegion$ */ package org.jboss.netty.channel; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/000077500000000000000000000000001225554127700254775ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/ChannelRunnableWrapper.java000066400000000000000000000030001225554127700327330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.DefaultChannelFuture; public class ChannelRunnableWrapper extends DefaultChannelFuture implements Runnable { private final Runnable task; private boolean started; public ChannelRunnableWrapper(Channel channel, Runnable task) { super(channel, true); this.task = task; } public void run() { synchronized (this) { if (!isCancelled()) { started = true; } else { return; } } try { task.run(); setSuccess(); } catch (Throwable t) { setFailure(t); } } @Override public synchronized boolean cancel() { if (started) { return false; } return super.cancel(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/ClientSocketChannelFactory.java000066400000000000000000000020541225554127700335530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; /** * A {@link ChannelFactory} which creates a client-side {@link SocketChannel}. * * @apiviz.has org.jboss.netty.channel.socket.SocketChannel oneway - - creates */ public interface ClientSocketChannelFactory extends ChannelFactory { SocketChannel newChannel(ChannelPipeline pipeline); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/DatagramChannel.java000066400000000000000000000034231225554127700313550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; /** * A UDP/IP {@link Channel} which is created by {@link DatagramChannelFactory}. * * @apiviz.landmark * @apiviz.composedOf org.jboss.netty.channel.socket.DatagramChannelConfig */ public interface DatagramChannel extends Channel { DatagramChannelConfig getConfig(); InetSocketAddress getLocalAddress(); InetSocketAddress getRemoteAddress(); /** * Joins a multicast group. */ ChannelFuture joinGroup(InetAddress multicastAddress); /** * Joins the specified multicast group at the specified interface. */ ChannelFuture joinGroup(InetSocketAddress multicastAddress, NetworkInterface networkInterface); /** * Leaves a multicast group. */ ChannelFuture leaveGroup(InetAddress multicastAddress); /** * Leaves a multicast group on a specified local interface. */ ChannelFuture leaveGroup(InetSocketAddress multicastAddress, NetworkInterface networkInterface); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/DatagramChannelConfig.java000066400000000000000000000152261225554127700325070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.StandardSocketOptions; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.FixedReceiveBufferSizePredictor; import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import org.jboss.netty.channel.ReceiveBufferSizePredictorFactory; /** * A {@link ChannelConfig} for a {@link DatagramChannel}. * *

Available options

* * In addition to the options provided by {@link ChannelConfig}, * {@link DatagramChannelConfig} allows the following options in the option map: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NameAssociated setter method
{@code "broadcast"}{@link #setBroadcast(boolean)}
{@code "interface"}{@link #setInterface(InetAddress)}
{@code "loopbackModeDisabled"}{@link #setLoopbackModeDisabled(boolean)}
{@code "networkInterface"}{@link #setNetworkInterface(NetworkInterface)}
{@code "reuseAddress"}{@link #setReuseAddress(boolean)}
{@code "receiveBufferSize"}{@link #setReceiveBufferSize(int)}
{@code "receiveBufferSizePredictor"}{@link #setReceiveBufferSizePredictor(ReceiveBufferSizePredictor)}
{@code "receiveBufferSizePredictorFactory"}{@link #setReceiveBufferSizePredictorFactory(ReceiveBufferSizePredictorFactory)}
{@code "sendBufferSize"}{@link #setSendBufferSize(int)}
{@code "timeToLive"}{@link #setTimeToLive(int)}
{@code "trafficClass"}{@link #setTrafficClass(int)}
*/ public interface DatagramChannelConfig extends ChannelConfig { /** * Gets the {@link StandardSocketOptions#SO_SNDBUF} option. */ int getSendBufferSize(); /** * Sets the {@link StandardSocketOptions#SO_SNDBUF} option. */ void setSendBufferSize(int sendBufferSize); /** * Gets the {@link StandardSocketOptions#SO_RCVBUF} option. */ int getReceiveBufferSize(); /** * Sets the {@link StandardSocketOptions#SO_RCVBUF} option. */ void setReceiveBufferSize(int receiveBufferSize); /** * Gets the {@link StandardSocketOptions#IP_TOS} option. */ int getTrafficClass(); /** * Gets the {@link StandardSocketOptions#IP_TOS} option. */ void setTrafficClass(int trafficClass); /** * Gets the {@link StandardSocketOptions#SO_REUSEADDR} option. */ boolean isReuseAddress(); /** * Sets the {@link StandardSocketOptions#SO_REUSEADDR} option. */ void setReuseAddress(boolean reuseAddress); /** * Gets the {@link StandardSocketOptions#SO_BROADCAST} option. */ boolean isBroadcast(); /** * Sets the {@link StandardSocketOptions#SO_BROADCAST} option. */ void setBroadcast(boolean broadcast); /** * Gets the {@link StandardSocketOptions#IP_MULTICAST_LOOP} option. */ boolean isLoopbackModeDisabled(); /** * Sets the {@link StandardSocketOptions#IP_MULTICAST_LOOP} option. * * @param loopbackModeDisabled * {@code true} if and only if the loopback mode has been disabled */ void setLoopbackModeDisabled(boolean loopbackModeDisabled); /** * Gets the {@link StandardSocketOptions#IP_MULTICAST_TTL} option. */ int getTimeToLive(); /** * Sets the {@link StandardSocketOptions#IP_MULTICAST_TTL} option. */ void setTimeToLive(int ttl); /** * Gets the address of the network interface used for multicast packets. */ InetAddress getInterface(); /** * Sets the address of the network interface used for multicast packets. */ void setInterface(InetAddress interfaceAddress); /** * Gets the {@link StandardSocketOptions#IP_MULTICAST_IF} option. */ NetworkInterface getNetworkInterface(); /** * Sets the {@link StandardSocketOptions#IP_MULTICAST_IF} option. */ void setNetworkInterface(NetworkInterface networkInterface); /** * Returns the {@link ReceiveBufferSizePredictor} which predicts the * number of readable bytes in the socket receive buffer. The default * predictor is {@link FixedReceiveBufferSizePredictor}(768). */ ReceiveBufferSizePredictor getReceiveBufferSizePredictor(); /** * Sets the {@link ReceiveBufferSizePredictor} which predicts the * number of readable bytes in the socket receive buffer. The default * predictor is {@link FixedReceiveBufferSizePredictor}(768). */ void setReceiveBufferSizePredictor(ReceiveBufferSizePredictor predictor); /** * Returns the {@link ReceiveBufferSizePredictorFactory} which creates a new * {@link ReceiveBufferSizePredictor} when a new channel is created and * no {@link ReceiveBufferSizePredictor} was set. If no predictor was set * for the channel, {@link #setReceiveBufferSizePredictor(ReceiveBufferSizePredictor)} * will be called with the new predictor. The default factory is * {@link FixedReceiveBufferSizePredictorFactory}(768). */ ReceiveBufferSizePredictorFactory getReceiveBufferSizePredictorFactory(); /** * Sets the {@link ReceiveBufferSizePredictor} which creates a new * {@link ReceiveBufferSizePredictor} when a new channel is created and * no {@link ReceiveBufferSizePredictor} was set. If no predictor was set * for the channel, {@link #setReceiveBufferSizePredictor(ReceiveBufferSizePredictor)} * will be called with the new predictor. The default factory is * {@link FixedReceiveBufferSizePredictorFactory}(768). */ void setReceiveBufferSizePredictorFactory(ReceiveBufferSizePredictorFactory predictorFactory); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/DatagramChannelFactory.java000066400000000000000000000020421225554127700327010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; /** * A {@link ChannelFactory} which creates a {@link DatagramChannel}. * * @apiviz.has org.jboss.netty.channel.socket.DatagramChannel oneway - - creates */ public interface DatagramChannelFactory extends ChannelFactory { DatagramChannel newChannel(ChannelPipeline pipeline); } DefaultDatagramChannelConfig.java000066400000000000000000000232501225554127700337310ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.SocketException; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.DefaultChannelConfig; import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import org.jboss.netty.channel.ReceiveBufferSizePredictorFactory; import org.jboss.netty.util.internal.ConversionUtil; /** * The default {@link DatagramChannelConfig} implementation. */ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implements DatagramChannelConfig { private static final ReceiveBufferSizePredictorFactory DEFAULT_PREDICTOR_FACTORY = new FixedReceiveBufferSizePredictorFactory(768); private final DatagramSocket socket; private volatile ReceiveBufferSizePredictor predictor; private volatile ReceiveBufferSizePredictorFactory predictorFactory = DEFAULT_PREDICTOR_FACTORY; /** * Creates a new instance. */ public DefaultDatagramChannelConfig(DatagramSocket socket) { if (socket == null) { throw new NullPointerException("socket"); } this.socket = socket; } @Override public boolean setOption(String key, Object value) { if (super.setOption(key, value)) { return true; } if ("broadcast".equals(key)) { setBroadcast(ConversionUtil.toBoolean(value)); } else if ("receiveBufferSize".equals(key)) { setReceiveBufferSize(ConversionUtil.toInt(value)); } else if ("sendBufferSize".equals(key)) { setSendBufferSize(ConversionUtil.toInt(value)); } else if ("receiveBufferSizePredictorFactory".equals(key)) { setReceiveBufferSizePredictorFactory((ReceiveBufferSizePredictorFactory) value); } else if ("receiveBufferSizePredictor".equals(key)) { setReceiveBufferSizePredictor((ReceiveBufferSizePredictor) value); } else if ("reuseAddress".equals(key)) { setReuseAddress(ConversionUtil.toBoolean(value)); } else if ("loopbackModeDisabled".equals(key)) { setLoopbackModeDisabled(ConversionUtil.toBoolean(value)); } else if ("interface".equals(key)) { setInterface((InetAddress) value); } else if ("networkInterface".equals(key)) { setNetworkInterface((NetworkInterface) value); } else if ("timeToLive".equals(key)) { setTimeToLive(ConversionUtil.toInt(value)); } else if ("trafficClass".equals(key)) { setTrafficClass(ConversionUtil.toInt(value)); } else { return false; } return true; } public boolean isBroadcast() { try { return socket.getBroadcast(); } catch (SocketException e) { throw new ChannelException(e); } } public void setBroadcast(boolean broadcast) { try { socket.setBroadcast(broadcast); } catch (SocketException e) { throw new ChannelException(e); } } public InetAddress getInterface() { if (socket instanceof MulticastSocket) { try { return ((MulticastSocket) socket).getInterface(); } catch (SocketException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public void setInterface(InetAddress interfaceAddress) { if (socket instanceof MulticastSocket) { try { ((MulticastSocket) socket).setInterface(interfaceAddress); } catch (SocketException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public boolean isLoopbackModeDisabled() { if (socket instanceof MulticastSocket) { try { return ((MulticastSocket) socket).getLoopbackMode(); } catch (SocketException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public void setLoopbackModeDisabled(boolean loopbackModeDisabled) { if (socket instanceof MulticastSocket) { try { ((MulticastSocket) socket).setLoopbackMode(loopbackModeDisabled); } catch (SocketException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public NetworkInterface getNetworkInterface() { if (socket instanceof MulticastSocket) { try { return ((MulticastSocket) socket).getNetworkInterface(); } catch (SocketException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public void setNetworkInterface(NetworkInterface networkInterface) { if (socket instanceof MulticastSocket) { try { ((MulticastSocket) socket).setNetworkInterface(networkInterface); } catch (SocketException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public boolean isReuseAddress() { try { return socket.getReuseAddress(); } catch (SocketException e) { throw new ChannelException(e); } } public void setReuseAddress(boolean reuseAddress) { try { socket.setReuseAddress(reuseAddress); } catch (SocketException e) { throw new ChannelException(e); } } public int getReceiveBufferSize() { try { return socket.getReceiveBufferSize(); } catch (SocketException e) { throw new ChannelException(e); } } public void setReceiveBufferSize(int receiveBufferSize) { try { socket.setReceiveBufferSize(receiveBufferSize); } catch (SocketException e) { throw new ChannelException(e); } } public int getSendBufferSize() { try { return socket.getSendBufferSize(); } catch (SocketException e) { throw new ChannelException(e); } } public void setSendBufferSize(int sendBufferSize) { try { socket.setSendBufferSize(sendBufferSize); } catch (SocketException e) { throw new ChannelException(e); } } public int getTimeToLive() { if (socket instanceof MulticastSocket) { try { return ((MulticastSocket) socket).getTimeToLive(); } catch (IOException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public void setTimeToLive(int ttl) { if (socket instanceof MulticastSocket) { try { ((MulticastSocket) socket).setTimeToLive(ttl); } catch (IOException e) { throw new ChannelException(e); } } else { throw new UnsupportedOperationException(); } } public int getTrafficClass() { try { return socket.getTrafficClass(); } catch (SocketException e) { throw new ChannelException(e); } } public void setTrafficClass(int trafficClass) { try { socket.setTrafficClass(trafficClass); } catch (SocketException e) { throw new ChannelException(e); } } public ReceiveBufferSizePredictor getReceiveBufferSizePredictor() { ReceiveBufferSizePredictor predictor = this.predictor; if (predictor == null) { try { this.predictor = predictor = getReceiveBufferSizePredictorFactory().getPredictor(); } catch (Exception e) { throw new ChannelException( "Failed to create a new " + ReceiveBufferSizePredictor.class.getSimpleName() + '.', e); } } return predictor; } public void setReceiveBufferSizePredictor( ReceiveBufferSizePredictor predictor) { if (predictor == null) { throw new NullPointerException("predictor"); } this.predictor = predictor; } public ReceiveBufferSizePredictorFactory getReceiveBufferSizePredictorFactory() { return predictorFactory; } public void setReceiveBufferSizePredictorFactory(ReceiveBufferSizePredictorFactory predictorFactory) { if (predictorFactory == null) { throw new NullPointerException("predictorFactory"); } this.predictorFactory = predictorFactory; } } DefaultServerSocketChannelConfig.java000066400000000000000000000063271225554127700346360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.ServerSocket; import java.net.SocketException; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.DefaultServerChannelConfig; import org.jboss.netty.util.internal.ConversionUtil; /** * The default {@link ServerSocketChannelConfig} implementation. */ public class DefaultServerSocketChannelConfig extends DefaultServerChannelConfig implements ServerSocketChannelConfig { private final ServerSocket socket; private volatile int backlog; /** * Creates a new instance. */ public DefaultServerSocketChannelConfig(ServerSocket socket) { if (socket == null) { throw new NullPointerException("socket"); } this.socket = socket; } @Override public boolean setOption(String key, Object value) { if (super.setOption(key, value)) { return true; } if ("receiveBufferSize".equals(key)) { setReceiveBufferSize(ConversionUtil.toInt(value)); } else if ("reuseAddress".equals(key)) { setReuseAddress(ConversionUtil.toBoolean(value)); } else if ("backlog".equals(key)) { setBacklog(ConversionUtil.toInt(value)); } else { return false; } return true; } public boolean isReuseAddress() { try { return socket.getReuseAddress(); } catch (SocketException e) { throw new ChannelException(e); } } public void setReuseAddress(boolean reuseAddress) { try { socket.setReuseAddress(reuseAddress); } catch (SocketException e) { throw new ChannelException(e); } } public int getReceiveBufferSize() { try { return socket.getReceiveBufferSize(); } catch (SocketException e) { throw new ChannelException(e); } } public void setReceiveBufferSize(int receiveBufferSize) { try { socket.setReceiveBufferSize(receiveBufferSize); } catch (SocketException e) { throw new ChannelException(e); } } public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { socket.setPerformancePreferences(connectionTime, latency, bandwidth); } public int getBacklog() { return backlog; } public void setBacklog(int backlog) { if (backlog < 0) { throw new IllegalArgumentException("backlog: " + backlog); } this.backlog = backlog; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/DefaultSocketChannelConfig.java000066400000000000000000000126111225554127700335170ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.DefaultChannelConfig; import org.jboss.netty.util.internal.ConversionUtil; import java.net.Socket; import java.net.SocketException; /** * The default {@link SocketChannelConfig} implementation. */ public class DefaultSocketChannelConfig extends DefaultChannelConfig implements SocketChannelConfig { private final Socket socket; /** * Creates a new instance. */ public DefaultSocketChannelConfig(Socket socket) { if (socket == null) { throw new NullPointerException("socket"); } this.socket = socket; } @Override public boolean setOption(String key, Object value) { if (super.setOption(key, value)) { return true; } if ("receiveBufferSize".equals(key)) { setReceiveBufferSize(ConversionUtil.toInt(value)); } else if ("sendBufferSize".equals(key)) { setSendBufferSize(ConversionUtil.toInt(value)); } else if ("tcpNoDelay".equals(key)) { setTcpNoDelay(ConversionUtil.toBoolean(value)); } else if ("keepAlive".equals(key)) { setKeepAlive(ConversionUtil.toBoolean(value)); } else if ("reuseAddress".equals(key)) { setReuseAddress(ConversionUtil.toBoolean(value)); } else if ("soLinger".equals(key)) { setSoLinger(ConversionUtil.toInt(value)); } else if ("trafficClass".equals(key)) { setTrafficClass(ConversionUtil.toInt(value)); } else { return false; } return true; } public int getReceiveBufferSize() { try { return socket.getReceiveBufferSize(); } catch (SocketException e) { throw new ChannelException(e); } } public int getSendBufferSize() { try { return socket.getSendBufferSize(); } catch (SocketException e) { throw new ChannelException(e); } } public int getSoLinger() { try { return socket.getSoLinger(); } catch (SocketException e) { throw new ChannelException(e); } } public int getTrafficClass() { try { return socket.getTrafficClass(); } catch (SocketException e) { throw new ChannelException(e); } } public boolean isKeepAlive() { try { return socket.getKeepAlive(); } catch (SocketException e) { throw new ChannelException(e); } } public boolean isReuseAddress() { try { return socket.getReuseAddress(); } catch (SocketException e) { throw new ChannelException(e); } } public boolean isTcpNoDelay() { try { return socket.getTcpNoDelay(); } catch (SocketException e) { throw new ChannelException(e); } } public void setKeepAlive(boolean keepAlive) { try { socket.setKeepAlive(keepAlive); } catch (SocketException e) { throw new ChannelException(e); } } public void setPerformancePreferences( int connectionTime, int latency, int bandwidth) { socket.setPerformancePreferences(connectionTime, latency, bandwidth); } public void setReceiveBufferSize(int receiveBufferSize) { try { socket.setReceiveBufferSize(receiveBufferSize); } catch (SocketException e) { throw new ChannelException(e); } } public void setReuseAddress(boolean reuseAddress) { try { socket.setReuseAddress(reuseAddress); } catch (SocketException e) { throw new ChannelException(e); } } public void setSendBufferSize(int sendBufferSize) { try { socket.setSendBufferSize(sendBufferSize); } catch (SocketException e) { throw new ChannelException(e); } } public void setSoLinger(int soLinger) { try { if (soLinger < 0) { socket.setSoLinger(false, 0); } else { socket.setSoLinger(true, soLinger); } } catch (SocketException e) { throw new ChannelException(e); } } public void setTcpNoDelay(boolean tcpNoDelay) { try { socket.setTcpNoDelay(tcpNoDelay); } catch (SocketException e) { throw new ChannelException(e); } } public void setTrafficClass(int trafficClass) { try { socket.setTrafficClass(trafficClass); } catch (SocketException e) { throw new ChannelException(e); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/InternetProtocolFamily.java000066400000000000000000000014111225554127700330130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; /** * Internet Protocol (IP) families */ public enum InternetProtocolFamily { IPv4, IPv6 } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/ServerSocketChannel.java000066400000000000000000000021571225554127700322570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.InetSocketAddress; import org.jboss.netty.channel.ServerChannel; /** * A TCP/IP {@link ServerChannel} which accepts incoming TCP/IP connections. * * @apiviz.landmark * @apiviz.composedOf org.jboss.netty.channel.socket.ServerSocketChannelConfig */ public interface ServerSocketChannel extends ServerChannel { ServerSocketChannelConfig getConfig(); InetSocketAddress getLocalAddress(); InetSocketAddress getRemoteAddress(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/ServerSocketChannelConfig.java000066400000000000000000000047201225554127700334030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.ServerSocket; import java.net.StandardSocketOptions; import org.jboss.netty.channel.ChannelConfig; /** * A {@link ChannelConfig} for a {@link ServerSocketChannel}. * *

Available options

* * In addition to the options provided by {@link ChannelConfig}, * {@link ServerSocketChannelConfig} allows the following options in the * option map: * * * * * * * * * * * *
NameAssociated setter method
{@code "backlog"}{@link #setBacklog(int)}
{@code "reuseAddress"}{@link #setReuseAddress(boolean)}
{@code "receiveBufferSize"}{@link #setReceiveBufferSize(int)}
*/ public interface ServerSocketChannelConfig extends ChannelConfig { /** * Gets the backlog value to specify when the channel binds to a local * address. */ int getBacklog(); /** * Sets the backlog value to specify when the channel binds to a local * address. */ void setBacklog(int backlog); /** * Gets the {@link StandardSocketOptions#SO_REUSEADDR} option. */ boolean isReuseAddress(); /** * Sets the {@link StandardSocketOptions#SO_REUSEADDR} option. */ void setReuseAddress(boolean reuseAddress); /** * Gets the {@link StandardSocketOptions#SO_RCVBUF} option. */ int getReceiveBufferSize(); /** * Sets the {@link StandardSocketOptions#SO_RCVBUF} option. */ void setReceiveBufferSize(int receiveBufferSize); /** * Sets the performance preferences as specified in * {@link ServerSocket#setPerformancePreferences(int, int, int)}. */ void setPerformancePreferences(int connectionTime, int latency, int bandwidth); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/ServerSocketChannelFactory.java000066400000000000000000000021551225554127700336050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ServerChannelFactory; /** * A {@link ChannelFactory} which creates a {@link ServerSocketChannel}. * * @apiviz.has org.jboss.netty.channel.socket.ServerSocketChannel oneway - - creates */ public interface ServerSocketChannelFactory extends ServerChannelFactory { ServerSocketChannel newChannel(ChannelPipeline pipeline); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/SocketChannel.java000066400000000000000000000022251225554127700310640ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.InetSocketAddress; import org.jboss.netty.channel.Channel; /** * A TCP/IP socket {@link Channel} which was either accepted by * {@link ServerSocketChannel} or created by {@link ClientSocketChannelFactory}. * * @apiviz.landmark * @apiviz.composedOf org.jboss.netty.channel.socket.SocketChannelConfig */ public interface SocketChannel extends Channel { SocketChannelConfig getConfig(); InetSocketAddress getLocalAddress(); InetSocketAddress getRemoteAddress(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/SocketChannelConfig.java000066400000000000000000000072221225554127700322140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.net.Socket; import java.net.StandardSocketOptions; import org.jboss.netty.channel.ChannelConfig; /** * A {@link ChannelConfig} for a {@link SocketChannel}. * *

Available options

* * In addition to the options provided by {@link ChannelConfig}, * {@link SocketChannelConfig} allows the following options in the option map: * * * * * * * * * * * * * * * * * * * *
NameAssociated setter method
{@code "keepAlive"}{@link #setKeepAlive(boolean)}
{@code "reuseAddress"}{@link #setReuseAddress(boolean)}
{@code "soLinger"}{@link #setSoLinger(int)}
{@code "tcpNoDelay"}{@link #setTcpNoDelay(boolean)}
{@code "receiveBufferSize"}{@link #setReceiveBufferSize(int)}
{@code "sendBufferSize"}{@link #setSendBufferSize(int)}
{@code "trafficClass"}{@link #setTrafficClass(int)}
*/ public interface SocketChannelConfig extends ChannelConfig { /** * Gets the {@link StandardSocketOptions#TCP_NODELAY} option. */ boolean isTcpNoDelay(); /** * Sets the {@link StandardSocketOptions#TCP_NODELAY} option. */ void setTcpNoDelay(boolean tcpNoDelay); /** * Gets the {@link StandardSocketOptions#SO_LINGER} option. */ int getSoLinger(); /** * Sets the {@link StandardSocketOptions#SO_LINGER} option. */ void setSoLinger(int soLinger); /** * Gets the {@link StandardSocketOptions#SO_SNDBUF} option. */ int getSendBufferSize(); /** * Sets the {@link StandardSocketOptions#SO_SNDBUF} option. */ void setSendBufferSize(int sendBufferSize); /** * Gets the {@link StandardSocketOptions#SO_RCVBUF} option. */ int getReceiveBufferSize(); /** * Sets the {@link StandardSocketOptions#SO_RCVBUF} option. */ void setReceiveBufferSize(int receiveBufferSize); /** * Gets the {@link StandardSocketOptions#SO_KEEPALIVE} option. */ boolean isKeepAlive(); /** * Sets the {@link StandardSocketOptions#SO_KEEPALIVE} option. */ void setKeepAlive(boolean keepAlive); /** * Gets the {@link StandardSocketOptions#IP_TOS} option. */ int getTrafficClass(); /** * Sets the {@link StandardSocketOptions#IP_TOS} option. */ void setTrafficClass(int trafficClass); /** * Gets the {@link StandardSocketOptions#SO_REUSEADDR} option. */ boolean isReuseAddress(); /** * Sets the {@link StandardSocketOptions#SO_REUSEADDR} option. */ void setReuseAddress(boolean reuseAddress); /** * Sets the performance preferences as specified in * {@link Socket#setPerformancePreferences(int, int, int)}. */ void setPerformancePreferences( int connectionTime, int latency, int bandwidth); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/Worker.java000066400000000000000000000020461225554127700276150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; /** * A {@link Worker} is responsible to dispatch IO operations * */ public interface Worker extends Runnable { /** * Execute the given {@link Runnable} in the IO-Thread. This may be now or * later once the IO-Thread do some other work. * * @param task * the {@link Runnable} to execute */ void executeInIoThread(Runnable task); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/000077500000000000000000000000001225554127700264565ustar00rootroot00000000000000HttpTunnelingClientSocketChannel.java000066400000000000000000000367151225554127700356620ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.http; import static org.jboss.netty.channel.Channels.*; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.NotYetConnectedException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.AbstractChannel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.DefaultChannelPipeline; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.handler.codec.http.DefaultHttpChunk; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestEncoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.handler.ssl.SslHandler; /** */ class HttpTunnelingClientSocketChannel extends AbstractChannel implements SocketChannel { final HttpTunnelingSocketChannelConfig config; volatile boolean requestHeaderWritten; final Object interestOpsLock = new Object(); final SocketChannel realChannel; private final ServletChannelHandler handler = new ServletChannelHandler(); HttpTunnelingClientSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, ClientSocketChannelFactory clientSocketChannelFactory) { super(null, factory, pipeline, sink); config = new HttpTunnelingSocketChannelConfig(this); DefaultChannelPipeline channelPipeline = new DefaultChannelPipeline(); channelPipeline.addLast("decoder", new HttpResponseDecoder()); channelPipeline.addLast("encoder", new HttpRequestEncoder()); channelPipeline.addLast("handler", handler); realChannel = clientSocketChannelFactory.newChannel(channelPipeline); fireChannelOpen(this); } public HttpTunnelingSocketChannelConfig getConfig() { return config; } public InetSocketAddress getLocalAddress() { return realChannel.getLocalAddress(); } public InetSocketAddress getRemoteAddress() { return realChannel.getRemoteAddress(); } public boolean isBound() { return realChannel.isBound(); } public boolean isConnected() { return realChannel.isConnected(); } @Override public int getInterestOps() { return realChannel.getInterestOps(); } @Override public boolean isWritable() { return realChannel.isWritable(); } @Override protected boolean setClosed() { return super.setClosed(); } @Override public ChannelFuture write(Object message, SocketAddress remoteAddress) { if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) { return super.write(message, null); } else { return getUnsupportedOperationFuture(); } } void bindReal(final SocketAddress localAddress, final ChannelFuture future) { realChannel.bind(localAddress).addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { if (f.isSuccess()) { future.setSuccess(); } else { future.setFailure(f.getCause()); } } }); } void connectReal(final SocketAddress remoteAddress, final ChannelFuture future) { final SocketChannel virtualChannel = this; realChannel.connect(remoteAddress).addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { final String serverName = config.getServerName(); final int serverPort = ((InetSocketAddress) remoteAddress).getPort(); final String serverPath = config.getServerPath(); if (f.isSuccess()) { // Configure SSL SSLContext sslContext = config.getSslContext(); ChannelFuture sslHandshakeFuture = null; if (sslContext != null) { // Create a new SSLEngine from the specified SSLContext. SSLEngine engine; if (serverName != null) { engine = sslContext.createSSLEngine(serverName, serverPort); } else { engine = sslContext.createSSLEngine(); } // Configure the SSLEngine. engine.setUseClientMode(true); engine.setEnableSessionCreation(config.isEnableSslSessionCreation()); String[] enabledCipherSuites = config.getEnabledSslCipherSuites(); if (enabledCipherSuites != null) { engine.setEnabledCipherSuites(enabledCipherSuites); } String[] enabledProtocols = config.getEnabledSslProtocols(); if (enabledProtocols != null) { engine.setEnabledProtocols(enabledProtocols); } SslHandler sslHandler = new SslHandler(engine); realChannel.getPipeline().addFirst("ssl", sslHandler); sslHandshakeFuture = sslHandler.handshake(); } // Send the HTTP request. final HttpRequest req = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, serverPath); if (serverName != null) { req.headers().set(HttpHeaders.Names.HOST, serverName); } req.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream"); req.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); req.headers().set(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY); req.headers().set(HttpHeaders.Names.USER_AGENT, HttpTunnelingClientSocketChannel.class.getName()); if (sslHandshakeFuture == null) { realChannel.write(req); requestHeaderWritten = true; future.setSuccess(); fireChannelConnected(virtualChannel, remoteAddress); } else { sslHandshakeFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { if (f.isSuccess()) { realChannel.write(req); requestHeaderWritten = true; future.setSuccess(); fireChannelConnected(virtualChannel, remoteAddress); } else { future.setFailure(f.getCause()); fireExceptionCaught(virtualChannel, f.getCause()); } } }); } } else { future.setFailure(f.getCause()); fireExceptionCaught(virtualChannel, f.getCause()); } } }); } void writeReal(final ChannelBuffer a, final ChannelFuture future) { if (!requestHeaderWritten) { throw new NotYetConnectedException(); } final int size = a.readableBytes(); final ChannelFuture f; if (size == 0) { f = realChannel.write(ChannelBuffers.EMPTY_BUFFER); } else { f = realChannel.write(new DefaultHttpChunk(a)); } f.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { if (f.isSuccess()) { future.setSuccess(); if (size != 0) { fireWriteComplete(HttpTunnelingClientSocketChannel.this, size); } } else { future.setFailure(f.getCause()); } } }); } private ChannelFuture writeLastChunk() { if (!requestHeaderWritten) { return failedFuture(this, new NotYetConnectedException()); } else { return realChannel.write(HttpChunk.LAST_CHUNK); } } void setInterestOpsReal(final int interestOps, final ChannelFuture future) { realChannel.setInterestOps(interestOps).addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { if (f.isSuccess()) { future.setSuccess(); } else { future.setFailure(f.getCause()); } } }); } void disconnectReal(final ChannelFuture future) { writeLastChunk().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { realChannel.disconnect().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { if (f.isSuccess()) { future.setSuccess(); } else { future.setFailure(f.getCause()); } } }); } }); } void unbindReal(final ChannelFuture future) { writeLastChunk().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { realChannel.unbind().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { if (f.isSuccess()) { future.setSuccess(); } else { future.setFailure(f.getCause()); } } }); } }); } void closeReal(final ChannelFuture future) { writeLastChunk().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { realChannel.close().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) { // Note: If 'future' refers to the closeFuture, // setSuccess() and setFailure() do nothing. // AbstractChannel.setClosed() should be called instead. // (See AbstractChannel.ChannelCloseFuture) if (f.isSuccess()) { future.setSuccess(); } else { future.setFailure(f.getCause()); } // Notify the closeFuture. setClosed(); } }); } }); } final class ServletChannelHandler extends SimpleChannelUpstreamHandler { private volatile boolean readingChunks; final SocketChannel virtualChannel = HttpTunnelingClientSocketChannel.this; @Override public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { fireChannelBound(virtualChannel, (SocketAddress) e.getValue()); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!readingChunks) { HttpResponse res = (HttpResponse) e.getMessage(); if (res.getStatus().getCode() != HttpResponseStatus.OK.getCode()) { throw new ChannelException("Unexpected HTTP response status: " + res.getStatus()); } if (res.isChunked()) { readingChunks = true; } else { ChannelBuffer content = res.getContent(); if (content.readable()) { fireMessageReceived(HttpTunnelingClientSocketChannel.this, content); } // Reached to the end of response - close the request. closeReal(succeededFuture(virtualChannel)); } } else { HttpChunk chunk = (HttpChunk) e.getMessage(); if (!chunk.isLast()) { fireMessageReceived(HttpTunnelingClientSocketChannel.this, chunk.getContent()); } else { readingChunks = false; // Reached to the end of response - close the request. closeReal(succeededFuture(virtualChannel)); } } } @Override public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { fireChannelInterestChanged(virtualChannel); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { fireChannelDisconnected(virtualChannel); } @Override public void channelUnbound(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { fireChannelUnbound(virtualChannel); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { fireChannelClosed(virtualChannel); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { fireExceptionCaught(virtualChannel, e.getCause()); realChannel.close(); } } } HttpTunnelingClientSocketChannelFactory.java000066400000000000000000000040451225554127700372010ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.http; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.SocketChannel; /** * Creates a client-side {@link SocketChannel} which connects to an * {@link HttpTunnelingServlet} to communicate with the server application * behind the {@link HttpTunnelingServlet}. Please refer to the * package summary for * the detailed usage. * @apiviz.landmark */ public class HttpTunnelingClientSocketChannelFactory implements ClientSocketChannelFactory { private final ChannelSink sink = new HttpTunnelingClientSocketPipelineSink(); private final ClientSocketChannelFactory clientSocketChannelFactory; /** * Creates a new instance. */ public HttpTunnelingClientSocketChannelFactory(ClientSocketChannelFactory clientSocketChannelFactory) { this.clientSocketChannelFactory = clientSocketChannelFactory; } public SocketChannel newChannel(ChannelPipeline pipeline) { return new HttpTunnelingClientSocketChannel(this, pipeline, sink, clientSocketChannelFactory); } public void releaseExternalResources() { clientSocketChannelFactory.releaseExternalResources(); } public void shutdown() { clientSocketChannelFactory.shutdown(); } } HttpTunnelingClientSocketPipelineSink.java000066400000000000000000000051021225554127700366660ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.http; import java.net.SocketAddress; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.AbstractChannelSink; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; final class HttpTunnelingClientSocketPipelineSink extends AbstractChannelSink { public void eventSunk( ChannelPipeline pipeline, ChannelEvent e) throws Exception { HttpTunnelingClientSocketChannel channel = (HttpTunnelingClientSocketChannel) e.getChannel(); ChannelFuture future = e.getFuture(); if (e instanceof ChannelStateEvent) { ChannelStateEvent stateEvent = (ChannelStateEvent) e; ChannelState state = stateEvent.getState(); Object value = stateEvent.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { channel.closeReal(future); } break; case BOUND: if (value != null) { channel.bindReal((SocketAddress) value, future); } else { channel.unbindReal(future); } break; case CONNECTED: if (value != null) { channel.connectReal((SocketAddress) value, future); } else { channel.closeReal(future); } break; case INTEREST_OPS: channel.setInterestOpsReal(((Integer) value).intValue(), future); break; } } else if (e instanceof MessageEvent) { channel.writeReal((ChannelBuffer) ((MessageEvent) e).getMessage(), future); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/HttpTunnelingServlet.java000066400000000000000000000214521225554127700334750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.http; import java.io.EOFException; import java.io.IOException; import java.io.PushbackInputStream; import java.net.SocketAddress; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.local.DefaultLocalClientChannelFactory; import org.jboss.netty.channel.local.LocalAddress; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * An {@link HttpServlet} that proxies an incoming data to the actual server * and vice versa. Please refer to the * package summary for * the detailed usage. * @apiviz.landmark */ public class HttpTunnelingServlet extends HttpServlet { private static final long serialVersionUID = 4259910275899756070L; private static final String ENDPOINT = "endpoint"; static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpTunnelingServlet.class); private volatile SocketAddress remoteAddress; private volatile ChannelFactory channelFactory; @Override public void init() throws ServletException { ServletConfig config = getServletConfig(); String endpoint = config.getInitParameter(ENDPOINT); if (endpoint == null) { throw new ServletException("init-param '" + ENDPOINT + "' must be specified."); } try { remoteAddress = parseEndpoint(endpoint.trim()); } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException("Failed to parse an endpoint.", e); } try { channelFactory = createChannelFactory(remoteAddress); } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException("Failed to create a channel factory.", e); } // Stuff for testing purpose //ServerBootstrap b = new ServerBootstrap(new DefaultLocalServerChannelFactory()); //b.getPipeline().addLast("logger", new LoggingHandler(getClass(), InternalLogLevel.INFO, true)); //b.getPipeline().addLast("handler", new EchoHandler()); //b.bind(remoteAddress); } protected SocketAddress parseEndpoint(String endpoint) throws Exception { if (endpoint.startsWith("local:")) { return new LocalAddress(endpoint.substring(6).trim()); } else { throw new ServletException( "Invalid or unknown endpoint: " + endpoint); } } protected ChannelFactory createChannelFactory(SocketAddress remoteAddress) throws Exception { if (remoteAddress instanceof LocalAddress) { return new DefaultLocalClientChannelFactory(); } else { throw new ServletException( "Unsupported remote address type: " + remoteAddress.getClass().getName()); } } @Override public void destroy() { try { destroyChannelFactory(channelFactory); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn("Failed to destroy a channel factory.", e); } } } protected void destroyChannelFactory(ChannelFactory factory) throws Exception { factory.releaseExternalResources(); } @Override protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if (!"POST".equalsIgnoreCase(req.getMethod())) { if (logger.isWarnEnabled()) { logger.warn("Unallowed method: " + req.getMethod()); } res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } final ChannelPipeline pipeline = Channels.pipeline(); final ServletOutputStream out = res.getOutputStream(); final OutboundConnectionHandler handler = new OutboundConnectionHandler(out); pipeline.addLast("handler", handler); Channel channel = channelFactory.newChannel(pipeline); ChannelFuture future = channel.connect(remoteAddress).awaitUninterruptibly(); if (!future.isSuccess()) { if (logger.isWarnEnabled()) { Throwable cause = future.getCause(); logger.warn("Endpoint unavailable: " + cause.getMessage(), cause); } res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } ChannelFuture lastWriteFuture = null; try { res.setStatus(HttpServletResponse.SC_OK); res.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream"); res.setHeader(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY); // Initiate chunked encoding by flushing the headers. out.flush(); PushbackInputStream in = new PushbackInputStream(req.getInputStream()); while (channel.isConnected()) { ChannelBuffer buffer; try { buffer = read(in); } catch (EOFException e) { break; } if (buffer == null) { break; } lastWriteFuture = channel.write(buffer); } } finally { if (lastWriteFuture == null) { channel.close(); } else { lastWriteFuture.addListener(ChannelFutureListener.CLOSE); } } } private static ChannelBuffer read(PushbackInputStream in) throws IOException { byte[] buf; int readBytes; int bytesToRead = in.available(); if (bytesToRead > 0) { buf = new byte[bytesToRead]; readBytes = in.read(buf); } else if (bytesToRead == 0) { int b = in.read(); if (b < 0 || in.available() < 0) { return null; } in.unread(b); bytesToRead = in.available(); buf = new byte[bytesToRead]; readBytes = in.read(buf); } else { return null; } assert readBytes > 0; ChannelBuffer buffer; if (readBytes == buf.length) { buffer = ChannelBuffers.wrappedBuffer(buf); } else { // A rare case, but it sometimes happen. buffer = ChannelBuffers.wrappedBuffer(buf, 0, readBytes); } return buffer; } private static final class OutboundConnectionHandler extends SimpleChannelUpstreamHandler { private final ServletOutputStream out; public OutboundConnectionHandler(ServletOutputStream out) { this.out = out; } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer) e.getMessage(); synchronized (this) { buffer.readBytes(out, buffer.readableBytes()); out.flush(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (logger.isWarnEnabled()) { logger.warn("Unexpected exception while HTTP tunneling", e.getCause()); } e.getChannel().close(); } } } HttpTunnelingSocketChannelConfig.java000066400000000000000000000242101225554127700356340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.http; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.channel.socket.SocketChannelConfig; import org.jboss.netty.util.internal.ConversionUtil; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; import java.util.Map; import java.util.Map.Entry; /** * The {@link ChannelConfig} of a client-side HTTP tunneling * {@link SocketChannel}. A {@link SocketChannel} created by * {@link HttpTunnelingClientSocketChannelFactory} will return an instance of * this configuration type for {@link SocketChannel#getConfig()}. * *

Available options

* * In addition to the options provided by {@link SocketChannelConfig}, * {@link HttpTunnelingSocketChannelConfig} allows the following options in * the option map: * * * * * * * * * * * * * *
NameAssociated setter method
{@code "sslContext"}{@link #setSslContext(SSLContext)}
{@code "enabledSslCiperSuites"}{@link #setEnabledSslCipherSuites(String[])}
{@code "enabledSslProtocols"}{@link #setEnabledSslProtocols(String[])}
{@code "enableSslSessionCreation"}{@link #setEnableSslSessionCreation(boolean)}
* @apiviz.landmark */ public final class HttpTunnelingSocketChannelConfig implements SocketChannelConfig { private final HttpTunnelingClientSocketChannel channel; private volatile String serverName; private volatile String serverPath = "/netty-tunnel"; private volatile SSLContext sslContext; private volatile String[] enabledSslCipherSuites; private volatile String[] enabledSslProtocols; private volatile boolean enableSslSessionCreation = true; /** * Creates a new instance. */ HttpTunnelingSocketChannelConfig(HttpTunnelingClientSocketChannel channel) { this.channel = channel; } /** * Returns the host name of the HTTP server. If {@code null}, the * {@code "Host"} header is not sent by the HTTP tunneling client. */ public String getServerName() { return serverName; } /** * Sets the host name of the HTTP server. If {@code null}, the * {@code "Host"} header is not sent by the HTTP tunneling client. */ public void setServerName(String serverName) { this.serverName = serverName; } /** * Returns the path where the {@link HttpTunnelingServlet} is mapped to. * The default value is {@code "/netty-tunnel"}. */ public String getServerPath() { return serverPath; } /** * Sets the path where the {@link HttpTunnelingServlet} is mapped to. * The default value is {@code "/netty-tunnel"}. */ public void setServerPath(String serverPath) { if (serverPath == null) { throw new NullPointerException("serverPath"); } this.serverPath = serverPath; } /** * Returns the {@link SSLContext} which is used to establish an HTTPS * connection. If {@code null}, a plain-text HTTP connection is established. */ public SSLContext getSslContext() { return sslContext; } /** * Sets the {@link SSLContext} which is used to establish an HTTPS connection. * If {@code null}, a plain-text HTTP connection is established. */ public void setSslContext(SSLContext sslContext) { this.sslContext = sslContext; } /** * Returns the cipher suites enabled for use on an {@link SSLEngine}. * If {@code null}, the default value will be used. * * @see SSLEngine#getEnabledCipherSuites() */ public String[] getEnabledSslCipherSuites() { String[] suites = enabledSslCipherSuites; if (suites == null) { return null; } else { return suites.clone(); } } /** * Sets the cipher suites enabled for use on an {@link SSLEngine}. * If {@code null}, the default value will be used. * * @see SSLEngine#setEnabledCipherSuites(String[]) */ public void setEnabledSslCipherSuites(String[] suites) { if (suites == null) { enabledSslCipherSuites = null; } else { enabledSslCipherSuites = suites.clone(); } } /** * Returns the protocol versions enabled for use on an {@link SSLEngine}. * * @see SSLEngine#getEnabledProtocols() */ public String[] getEnabledSslProtocols() { String[] protocols = enabledSslProtocols; if (protocols == null) { return null; } else { return protocols.clone(); } } /** * Sets the protocol versions enabled for use on an {@link SSLEngine}. * * @see SSLEngine#setEnabledProtocols(String[]) */ public void setEnabledSslProtocols(String[] protocols) { if (protocols == null) { enabledSslProtocols = null; } else { enabledSslProtocols = protocols.clone(); } } /** * Returns {@code true} if new {@link SSLSession}s may be established by * an {@link SSLEngine}. * * @see SSLEngine#getEnableSessionCreation() */ public boolean isEnableSslSessionCreation() { return enableSslSessionCreation; } /** * Sets whether new {@link SSLSession}s may be established by an * {@link SSLEngine}. * * @see SSLEngine#setEnableSessionCreation(boolean) */ public void setEnableSslSessionCreation(boolean flag) { enableSslSessionCreation = flag; } public void setOptions(Map options) { for (Entry e: options.entrySet()) { setOption(e.getKey(), e.getValue()); } } public boolean setOption(String key, Object value) { if (channel.realChannel.getConfig().setOption(key, value)) { return true; } if ("serverName".equals(key)) { setServerName(String.valueOf(value)); } else if ("serverPath".equals(key)) { setServerPath(String.valueOf(value)); } else if ("sslContext".equals(key)) { setSslContext((SSLContext) value); } else if ("enabledSslCipherSuites".equals(key)) { setEnabledSslCipherSuites(ConversionUtil.toStringArray(value)); } else if ("enabledSslProtocols".equals(key)) { setEnabledSslProtocols(ConversionUtil.toStringArray(value)); } else if ("enableSslSessionCreation".equals(key)) { setEnableSslSessionCreation(ConversionUtil.toBoolean(value)); } else { return false; } return true; } public int getReceiveBufferSize() { return channel.realChannel.getConfig().getReceiveBufferSize(); } public int getSendBufferSize() { return channel.realChannel.getConfig().getSendBufferSize(); } public int getSoLinger() { return channel.realChannel.getConfig().getSoLinger(); } public int getTrafficClass() { return channel.realChannel.getConfig().getTrafficClass(); } public boolean isKeepAlive() { return channel.realChannel.getConfig().isKeepAlive(); } public boolean isReuseAddress() { return channel.realChannel.getConfig().isReuseAddress(); } public boolean isTcpNoDelay() { return channel.realChannel.getConfig().isTcpNoDelay(); } public void setKeepAlive(boolean keepAlive) { channel.realChannel.getConfig().setKeepAlive(keepAlive); } public void setPerformancePreferences( int connectionTime, int latency, int bandwidth) { channel.realChannel.getConfig().setPerformancePreferences(connectionTime, latency, bandwidth); } public void setReceiveBufferSize(int receiveBufferSize) { channel.realChannel.getConfig().setReceiveBufferSize(receiveBufferSize); } public void setReuseAddress(boolean reuseAddress) { channel.realChannel.getConfig().setReuseAddress(reuseAddress); } public void setSendBufferSize(int sendBufferSize) { channel.realChannel.getConfig().setSendBufferSize(sendBufferSize); } public void setSoLinger(int soLinger) { channel.realChannel.getConfig().setSoLinger(soLinger); } public void setTcpNoDelay(boolean tcpNoDelay) { channel.realChannel.getConfig().setTcpNoDelay(tcpNoDelay); } public void setTrafficClass(int trafficClass) { channel.realChannel.getConfig().setTrafficClass(trafficClass); } public ChannelBufferFactory getBufferFactory() { return channel.realChannel.getConfig().getBufferFactory(); } public int getConnectTimeoutMillis() { return channel.realChannel.getConfig().getConnectTimeoutMillis(); } public ChannelPipelineFactory getPipelineFactory() { return channel.realChannel.getConfig().getPipelineFactory(); } public void setBufferFactory(ChannelBufferFactory bufferFactory) { channel.realChannel.getConfig().setBufferFactory(bufferFactory); } public void setConnectTimeoutMillis(int connectTimeoutMillis) { channel.realChannel.getConfig().setConnectTimeoutMillis(connectTimeoutMillis); } public void setPipelineFactory(ChannelPipelineFactory pipelineFactory) { channel.realChannel.getConfig().setPipelineFactory(pipelineFactory); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/http/package-info.java000066400000000000000000000106231225554127700316470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * An HTTP-based client-side {@link org.jboss.netty.channel.socket.SocketChannel} * and its corresponding server-side Servlet implementation that make your * existing server application work in a firewalled network. * *

Deploying the HTTP tunnel as a Servlet

* * First, {@link org.jboss.netty.channel.socket.http.HttpTunnelingServlet} must be * configured in a web.xml. * *
 * <?xml version="1.0" encoding="UTF-8"?>
 * <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
 *             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 *             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
 *             version="2.4">
 *
 *   <servlet>
 *     <servlet-name>NettyTunnelingServlet</servlet-name>
 *     <servlet-class>org.jboss.netty.channel.socket.http.HttpTunnelingServlet</servlet-class>
 *     <!--
 *       The name of the channel, this should be a registered local channel.
 *       See LocalTransportRegister.
 *     -->
 *     <init-param>
 *       <param-name>endpoint</param-name>
 *       <param-value>local:myLocalServer</param-value>
 *     </init-param>
 *     <load-on-startup>1</load-on-startup>
 *   </servlet>
 *
 *   <servlet-mapping>
 *     <servlet-name>NettyTunnelingServlet</servlet-name>
 *     <url-pattern>/netty-tunnel</url-pattern>
 *   </servlet-mapping>
 * </web-app>
 * 
* * Second, you have to bind your Netty-based server application in the same * Servlet context or shared class loader space using the local transport * (see {@link org.jboss.netty.channel.local.LocalServerChannelFactory}.) * You can use your favorite IoC framework such as JBoss Microcontainer, Guice, * and Spring to do this. The following example shows how to bind an echo * server to the endpoint specifed above (web.xml) in JBossAS 5: * *
 * <bean name="my-local-echo-server"
 *       class="org.jboss.netty.example.http.tunnel.LocalEchoServerRegistration" />
 *
 * ...
 *
 * package org.jboss.netty.example.http.tunnel;
 * ...
 *
 * public class LocalEchoServerRegistration {
 *
 *     private final ChannelFactory factory = new DefaultLocalServerChannelFactory();
 *     private volatile Channel serverChannel;
 *
 *     public void start() {
 *         ServerBootstrap serverBootstrap = new ServerBootstrap(factory);
 *         EchoHandler handler = new EchoHandler();
 *         serverBootstrap.getPipeline().addLast("handler", handler);
 *
 *         // Note that "myLocalServer" is the endpoint which was specified in web.xml.
 *         serverChannel = serverBootstrap.bind(new LocalAddress("myLocalServer"));
 *     }
 *
 *     public void stop() {
 *         serverChannel.close();
 *     }
 * }
 * 
* *

Connecting to the HTTP tunnel

* * Once the tunnel has been configured, your client-side application needs only * a couple lines of changes. * *
 * ClientBootstrap b = new ClientBootstrap(
 *         new HttpTunnelingClientSocketChannelFactory(
 *                 new NioClientSocketChannelFactory(...)));
 *
 * // Configure the pipeline (or pipeline factory) here.
 * ...
 *
 * // The host name of the HTTP server
 * b.setOption("serverName", "example.com");
 * // The path to the HTTP tunneling Servlet, which was specified in in web.xml
 * b.setOption("serverPath", "contextPath/netty-tunnel");
 * b.connect(new InetSocketAddress("example.com", 80);
 * 
* * For more configuration parameters such as HTTPS options, * refer to {@link org.jboss.netty.channel.socket.http.HttpTunnelingSocketChannelConfig}. */ package org.jboss.netty.channel.socket.http; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/000077500000000000000000000000001225554127700262645ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioBossPool.java000066400000000000000000000115111225554127700330200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.internal.ExecutorUtil; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public abstract class AbstractNioBossPool implements BossPool, ExternalResourceReleasable { /** * The boss pool raises an exception unless all boss threads start and run within this timeout (in seconds.) */ private static final int INITIALIZATION_TIMEOUT = 10; private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractNioBossPool.class); private final Boss[] bosses; private final AtomicInteger bossIndex = new AtomicInteger(); private final Executor bossExecutor; private volatile boolean initialized; /** * Create a new instance * * @param bossExecutor the {@link Executor} to use for the {@link Boss}'s * @param bossCount the count of {@link Boss}'s to create */ AbstractNioBossPool(Executor bossExecutor, int bossCount) { this(bossExecutor, bossCount, true); } AbstractNioBossPool(Executor bossExecutor, int bossCount, boolean autoInit) { if (bossExecutor == null) { throw new NullPointerException("bossExecutor"); } if (bossCount <= 0) { throw new IllegalArgumentException( "bossCount (" + bossCount + ") " + "must be a positive integer."); } bosses = new Boss[bossCount]; this.bossExecutor = bossExecutor; if (autoInit) { init(); } } protected void init() { if (initialized) { throw new IllegalStateException("initialized already"); } initialized = true; for (int i = 0; i < bosses.length; i++) { bosses[i] = newBoss(bossExecutor); } waitForBossThreads(); } private void waitForBossThreads() { long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(INITIALIZATION_TIMEOUT); boolean warn = false; for (Boss boss: bosses) { if (!(boss instanceof AbstractNioSelector)) { continue; } AbstractNioSelector selector = (AbstractNioSelector) boss; long waitTime = deadline - System.nanoTime(); try { if (waitTime <= 0) { if (selector.thread == null) { warn = true; break; } } else if (!selector.startupLatch.await(waitTime, TimeUnit.NANOSECONDS)) { warn = true; break; } } catch (InterruptedException ignore) { // Stop waiting for the boss threads and let someone else take care of the interruption. Thread.currentThread().interrupt(); break; } } if (warn) { logger.warn( "Failed to get all boss threads ready within " + INITIALIZATION_TIMEOUT + " second(s). " + "Make sure to specify the executor which has more threads than the requested bossCount. " + "If unsure, use Executors.newCachedThreadPool()."); } } /** * Create a new {@link Boss} which uses the given {@link Executor} to service IO * * * @param executor the {@link Executor} to use * @return worker the new {@link Boss} */ protected abstract E newBoss(Executor executor); @SuppressWarnings("unchecked") public E nextBoss() { return (E) bosses[Math.abs(bossIndex.getAndIncrement() % bosses.length)]; } public void rebuildSelectors() { for (Boss boss: bosses) { boss.rebuildSelector(); } } public void releaseExternalResources() { shutdown(); ExecutorUtil.shutdownNow(bossExecutor); } public void shutdown() { for (Boss boss: bosses) { boss.shutdown(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioChannel.java000066400000000000000000000243631225554127700326410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.AbstractChannel; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.socket.nio.SocketSendBufferPool.SendBuffer; import org.jboss.netty.util.internal.ThreadLocalBoolean; import java.net.InetSocketAddress; import java.nio.channels.SelectableChannel; import java.nio.channels.WritableByteChannel; import java.util.Collection; import java.util.Iterator; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import static org.jboss.netty.channel.Channels.*; abstract class AbstractNioChannel extends AbstractChannel { /** * The {@link AbstractNioWorker}. */ final AbstractNioWorker worker; /** * Monitor object for synchronizing access to the {@link WriteRequestQueue}. */ final Object writeLock = new Object(); /** * WriteTask that performs write operations. */ final Runnable writeTask = new WriteTask(); /** * Indicates if there is a {@link WriteTask} in the task queue. */ final AtomicBoolean writeTaskInTaskQueue = new AtomicBoolean(); /** * Queue of write {@link MessageEvent}s. */ final Queue writeBufferQueue = new WriteRequestQueue(); /** * Keeps track of the number of bytes that the {@link WriteRequestQueue} currently * contains. */ final AtomicInteger writeBufferSize = new AtomicInteger(); /** * Keeps track of the highWaterMark. */ final AtomicInteger highWaterMarkCounter = new AtomicInteger(); /** * The current write {@link MessageEvent} */ MessageEvent currentWriteEvent; SendBuffer currentWriteBuffer; /** * Boolean that indicates that write operation is in progress. */ boolean inWriteNowLoop; boolean writeSuspended; private volatile InetSocketAddress localAddress; volatile InetSocketAddress remoteAddress; final C channel; protected AbstractNioChannel( Integer id, Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, AbstractNioWorker worker, C ch) { super(id, parent, factory, pipeline, sink); this.worker = worker; channel = ch; } protected AbstractNioChannel( Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, AbstractNioWorker worker, C ch) { super(parent, factory, pipeline, sink); this.worker = worker; channel = ch; } /** * Return the {@link AbstractNioWorker} that handle the IO of the * {@link AbstractNioChannel} * * @return worker */ public AbstractNioWorker getWorker() { return worker; } public InetSocketAddress getLocalAddress() { InetSocketAddress localAddress = this.localAddress; if (localAddress == null) { try { localAddress = getLocalSocketAddress(); if (localAddress.getAddress().isAnyLocalAddress()) { // Don't cache on a wildcard address so the correct one // will be cached once the channel is connected/bound return localAddress; } this.localAddress = localAddress; } catch (Throwable t) { // Sometimes fails on a closed socket in Windows. return null; } } return localAddress; } public InetSocketAddress getRemoteAddress() { InetSocketAddress remoteAddress = this.remoteAddress; if (remoteAddress == null) { try { this.remoteAddress = remoteAddress = getRemoteSocketAddress(); } catch (Throwable t) { // Sometimes fails on a closed socket in Windows. return null; } } return remoteAddress; } public abstract NioChannelConfig getConfig(); int getRawInterestOps() { return super.getInterestOps(); } void setRawInterestOpsNow(int interestOps) { setInterestOpsNow(interestOps); } @Override public int getInterestOps() { if (!isOpen()) { return Channel.OP_WRITE; } int interestOps = getRawInterestOps(); int writeBufferSize = this.writeBufferSize.get(); if (writeBufferSize != 0) { if (highWaterMarkCounter.get() > 0) { int lowWaterMark = getConfig().getWriteBufferLowWaterMark(); if (writeBufferSize >= lowWaterMark) { interestOps |= Channel.OP_WRITE; } else { interestOps &= ~Channel.OP_WRITE; } } else { int highWaterMark = getConfig().getWriteBufferHighWaterMark(); if (writeBufferSize >= highWaterMark) { interestOps |= Channel.OP_WRITE; } else { interestOps &= ~Channel.OP_WRITE; } } } else { interestOps &= ~Channel.OP_WRITE; } return interestOps; } @Override protected boolean setClosed() { return super.setClosed(); } abstract InetSocketAddress getLocalSocketAddress() throws Exception; abstract InetSocketAddress getRemoteSocketAddress() throws Exception; private final class WriteRequestQueue implements Queue { private final ThreadLocalBoolean notifying = new ThreadLocalBoolean(); private final Queue queue; public WriteRequestQueue() { queue = new ConcurrentLinkedQueue(); } public MessageEvent remove() { return queue.remove(); } public MessageEvent element() { return queue.element(); } public MessageEvent peek() { return queue.peek(); } public int size() { return queue.size(); } public boolean isEmpty() { return queue.isEmpty(); } public Iterator iterator() { return queue.iterator(); } public Object[] toArray() { return queue.toArray(); } public T[] toArray(T[] a) { return queue.toArray(a); } public boolean containsAll(Collection c) { return queue.containsAll(c); } public boolean addAll(Collection c) { return queue.addAll(c); } public boolean removeAll(Collection c) { return queue.removeAll(c); } public boolean retainAll(Collection c) { return queue.retainAll(c); } public void clear() { queue.clear(); } public boolean add(MessageEvent e) { return queue.add(e); } public boolean remove(Object o) { return queue.remove(o); } public boolean contains(Object o) { return queue.contains(o); } public boolean offer(MessageEvent e) { boolean success = queue.offer(e); assert success; int messageSize = getMessageSize(e); int newWriteBufferSize = writeBufferSize.addAndGet(messageSize); int highWaterMark = getConfig().getWriteBufferHighWaterMark(); if (newWriteBufferSize >= highWaterMark) { if (newWriteBufferSize - messageSize < highWaterMark) { highWaterMarkCounter.incrementAndGet(); if (!notifying.get()) { notifying.set(Boolean.TRUE); fireChannelInterestChanged(AbstractNioChannel.this); notifying.set(Boolean.FALSE); } } } return true; } public MessageEvent poll() { MessageEvent e = queue.poll(); if (e != null) { int messageSize = getMessageSize(e); int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize); int lowWaterMark = getConfig().getWriteBufferLowWaterMark(); if (newWriteBufferSize == 0 || newWriteBufferSize < lowWaterMark) { if (newWriteBufferSize + messageSize >= lowWaterMark) { highWaterMarkCounter.decrementAndGet(); if (isConnected() && !notifying.get()) { notifying.set(Boolean.TRUE); fireChannelInterestChanged(AbstractNioChannel.this); notifying.set(Boolean.FALSE); } } } } return e; } private int getMessageSize(MessageEvent e) { Object m = e.getMessage(); if (m instanceof ChannelBuffer) { return ((ChannelBuffer) m).readableBytes(); } return 0; } } private final class WriteTask implements Runnable { WriteTask() { } public void run() { writeTaskInTaskQueue.set(false); worker.writeFromTaskLoop(AbstractNioChannel.this); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioChannelSink.java000066400000000000000000000036241225554127700334630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.AbstractChannelSink; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.socket.ChannelRunnableWrapper; public abstract class AbstractNioChannelSink extends AbstractChannelSink { @Override public ChannelFuture execute(ChannelPipeline pipeline, final Runnable task) { Channel ch = pipeline.getChannel(); if (ch instanceof AbstractNioChannel) { AbstractNioChannel channel = (AbstractNioChannel) ch; ChannelRunnableWrapper wrapper = new ChannelRunnableWrapper(pipeline.getChannel(), task); channel.worker.executeInIoThread(wrapper); return wrapper; } return super.execute(pipeline, task); } @Override protected boolean isFireExceptionCaughtLater(ChannelEvent event, Throwable actualCause) { Channel channel = event.getChannel(); boolean fireLater = false; if (channel instanceof AbstractNioChannel) { fireLater = !AbstractNioWorker.isIoThread((AbstractNioChannel) channel); } return fireLater; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioSelector.java000066400000000000000000000362531225554127700330520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import org.jboss.netty.util.internal.DeadLockProofWorker; import java.io.IOException; import java.nio.channels.CancelledKeyException; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.ConcurrentModificationException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; abstract class AbstractNioSelector implements NioSelector { private static final AtomicInteger nextId = new AtomicInteger(); private final int id = nextId.incrementAndGet(); /** * Internal Netty logger. */ protected static final InternalLogger logger = InternalLoggerFactory .getInstance(AbstractNioSelector.class); private static final int CLEANUP_INTERVAL = 256; // XXX Hard-coded value, but won't need customization. /** * Executor used to execute {@link Runnable}s such as channel registration * task. */ private final Executor executor; /** * If this worker has been started thread will be a reference to the thread * used when starting. i.e. the current thread when the run method is executed. */ protected volatile Thread thread; /** * Count down to 0 when the I/O thread starts and {@link #thread} is set to non-null. */ final CountDownLatch startupLatch = new CountDownLatch(1); /** * The NIO {@link Selector}. */ protected volatile Selector selector; /** * Boolean that controls determines if a blocked Selector.select should * break out of its selection process. In our case we use a timeone for * the select method and the select method will block for that time unless * waken up. */ protected final AtomicBoolean wakenUp = new AtomicBoolean(); private final Queue taskQueue = new ConcurrentLinkedQueue(); private volatile int cancelledKeys; // should use AtomicInteger but we just need approximation private final CountDownLatch shutdownLatch = new CountDownLatch(1); private volatile boolean shutdown; AbstractNioSelector(Executor executor) { this(executor, null); } AbstractNioSelector(Executor executor, ThreadNameDeterminer determiner) { this.executor = executor; openSelector(determiner); } public void register(Channel channel, ChannelFuture future) { Runnable task = createRegisterTask(channel, future); registerTask(task); } protected final void registerTask(Runnable task) { taskQueue.add(task); Selector selector = this.selector; if (selector != null) { if (wakenUp.compareAndSet(false, true)) { selector.wakeup(); } } else { if (taskQueue.remove(task)) { // the selector was null this means the Worker has already been shutdown. throw new RejectedExecutionException("Worker has already been shutdown"); } } } protected final boolean isIoThread() { return Thread.currentThread() == thread; } public void rebuildSelector() { if (!isIoThread()) { taskQueue.add(new Runnable() { public void run() { rebuildSelector(); } }); return; } final Selector oldSelector = selector; final Selector newSelector; if (oldSelector == null) { return; } try { newSelector = SelectorUtil.open(); } catch (Exception e) { logger.warn("Failed to create a new Selector.", e); return; } // Register all channels to the new Selector. int nChannels = 0; for (;;) { try { for (SelectionKey key: oldSelector.keys()) { try { if (key.channel().keyFor(newSelector) != null) { continue; } int interestOps = key.interestOps(); key.cancel(); key.channel().register(newSelector, interestOps, key.attachment()); nChannels ++; } catch (Exception e) { logger.warn("Failed to re-register a Channel to the new Selector,", e); close(key); } } } catch (ConcurrentModificationException e) { // Probably due to concurrent modification of the key set. continue; } break; } selector = newSelector; try { // time to close the old selector as everything else is registered to the new one oldSelector.close(); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("Failed to close the old Selector.", t); } } logger.info("Migrated " + nChannels + " channel(s) to the new Selector,"); } public void run() { thread = Thread.currentThread(); startupLatch.countDown(); int selectReturnsImmediately = 0; Selector selector = this.selector; if (selector == null) { return; } // use 80% of the timeout for measure final long minSelectTimeout = SelectorUtil.SELECT_TIMEOUT_NANOS * 80 / 100; boolean wakenupFromLoop = false; for (;;) { wakenUp.set(false); try { long beforeSelect = System.nanoTime(); int selected = select(selector); if (SelectorUtil.EPOLL_BUG_WORKAROUND && selected == 0 && !wakenupFromLoop && !wakenUp.get()) { long timeBlocked = System.nanoTime() - beforeSelect; if (timeBlocked < minSelectTimeout) { boolean notConnected = false; // loop over all keys as the selector may was unblocked because of a closed channel for (SelectionKey key: selector.keys()) { SelectableChannel ch = key.channel(); try { if (ch instanceof DatagramChannel && !ch.isOpen() || ch instanceof SocketChannel && !((SocketChannel) ch).isConnected()) { notConnected = true; // cancel the key just to be on the safe side key.cancel(); } } catch (CancelledKeyException e) { // ignore } } if (notConnected) { selectReturnsImmediately = 0; } else { // returned before the minSelectTimeout elapsed with nothing select. // this may be the cause of the jdk epoll(..) bug, so increment the counter // which we use later to see if its really the jdk bug. selectReturnsImmediately ++; } } else { selectReturnsImmediately = 0; } if (selectReturnsImmediately == 1024) { // The selector returned immediately for 10 times in a row, // so recreate one selector as it seems like we hit the // famous epoll(..) jdk bug. rebuildSelector(); selector = this.selector; selectReturnsImmediately = 0; wakenupFromLoop = false; // try to select again continue; } } else { // reset counter selectReturnsImmediately = 0; } // 'wakenUp.compareAndSet(false, true)' is always evaluated // before calling 'selector.wakeup()' to reduce the wake-up // overhead. (Selector.wakeup() is an expensive operation.) // // However, there is a race condition in this approach. // The race condition is triggered when 'wakenUp' is set to // true too early. // // 'wakenUp' is set to true too early if: // 1) Selector is waken up between 'wakenUp.set(false)' and // 'selector.select(...)'. (BAD) // 2) Selector is waken up between 'selector.select(...)' and // 'if (wakenUp.get()) { ... }'. (OK) // // In the first case, 'wakenUp' is set to true and the // following 'selector.select(...)' will wake up immediately. // Until 'wakenUp' is set to false again in the next round, // 'wakenUp.compareAndSet(false, true)' will fail, and therefore // any attempt to wake up the Selector will fail, too, causing // the following 'selector.select(...)' call to block // unnecessarily. // // To fix this problem, we wake up the selector again if wakenUp // is true immediately after selector.select(...). // It is inefficient in that it wakes up the selector for both // the first case (BAD - wake-up required) and the second case // (OK - no wake-up required). if (wakenUp.get()) { wakenupFromLoop = true; selector.wakeup(); } else { wakenupFromLoop = false; } cancelledKeys = 0; processTaskQueue(); selector = this.selector; // processTaskQueue() can call rebuildSelector() if (shutdown) { this.selector = null; // process one time again processTaskQueue(); for (SelectionKey k: selector.keys()) { close(k); } try { selector.close(); } catch (IOException e) { logger.warn( "Failed to close a selector.", e); } shutdownLatch.countDown(); break; } else { process(selector); } } catch (Throwable t) { logger.warn( "Unexpected exception in the selector loop.", t); // Prevent possible consecutive immediate failures that lead to // excessive CPU consumption. try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore. } } } } /** * Start the {@link AbstractNioWorker} and return the {@link Selector} that will be used for * the {@link AbstractNioChannel}'s when they get registered */ private void openSelector(ThreadNameDeterminer determiner) { try { selector = SelectorUtil.open(); } catch (Throwable t) { throw new ChannelException("Failed to create a selector.", t); } // Start the worker thread with the new Selector. boolean success = false; try { DeadLockProofWorker.start(executor, newThreadRenamingRunnable(id, determiner)); success = true; } finally { if (!success) { // Release the Selector if the execution fails. try { selector.close(); } catch (Throwable t) { logger.warn("Failed to close a selector.", t); } selector = null; // The method will return to the caller at this point. } } assert selector != null && selector.isOpen(); } private void processTaskQueue() { for (;;) { final Runnable task = taskQueue.poll(); if (task == null) { break; } task.run(); try { cleanUpCancelledKeys(); } catch (IOException e) { // Ignore } } } protected final void increaseCancelledKeys() { cancelledKeys ++; } protected final boolean cleanUpCancelledKeys() throws IOException { if (cancelledKeys >= CLEANUP_INTERVAL) { cancelledKeys = 0; selector.selectNow(); return true; } return false; } public void shutdown() { if (isIoThread()) { throw new IllegalStateException("Must not be called from a I/O-Thread to prevent deadlocks!"); } Selector selector = this.selector; shutdown = true; if (selector != null) { selector.wakeup(); } try { shutdownLatch.await(); } catch (InterruptedException e) { logger.error("Interrupted while wait for resources to be released #" + id); Thread.currentThread().interrupt(); } } protected abstract void process(Selector selector) throws IOException; protected int select(Selector selector) throws IOException { return SelectorUtil.select(selector); } protected abstract void close(SelectionKey k); protected abstract ThreadRenamingRunnable newThreadRenamingRunnable(int id, ThreadNameDeterminer determiner); protected abstract Runnable createRegisterTask(Channel channel, ChannelFuture future); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioWorker.java000066400000000000000000000452111225554127700325350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.socket.Worker; import org.jboss.netty.channel.socket.nio.SocketSendBufferPool.SendBuffer; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import java.io.IOException; import java.nio.channels.AsynchronousCloseException; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.NotYetConnectedException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Queue; import java.util.Set; import java.util.concurrent.Executor; import static org.jboss.netty.channel.Channels.*; abstract class AbstractNioWorker extends AbstractNioSelector implements Worker { protected final SocketSendBufferPool sendBufferPool = new SocketSendBufferPool(); AbstractNioWorker(Executor executor) { super(executor); } AbstractNioWorker(Executor executor, ThreadNameDeterminer determiner) { super(executor, determiner); } public void executeInIoThread(Runnable task) { executeInIoThread(task, false); } /** * Execute the {@link Runnable} in a IO-Thread * * @param task * the {@link Runnable} to execute * @param alwaysAsync * {@code true} if the {@link Runnable} should be executed * in an async fashion even if the current Thread == IO Thread */ public void executeInIoThread(Runnable task, boolean alwaysAsync) { if (!alwaysAsync && isIoThread()) { task.run(); } else { registerTask(task); } } @Override protected void close(SelectionKey k) { AbstractNioChannel ch = (AbstractNioChannel) k.attachment(); close(ch, succeededFuture(ch)); } @Override protected ThreadRenamingRunnable newThreadRenamingRunnable(int id, ThreadNameDeterminer determiner) { return new ThreadRenamingRunnable(this, "New I/O worker #" + id, determiner); } @Override public void run() { super.run(); sendBufferPool.releaseExternalResources(); } @Override protected void process(Selector selector) throws IOException { Set selectedKeys = selector.selectedKeys(); // check if the set is empty and if so just return to not create garbage by // creating a new Iterator every time even if there is nothing to process. // See https://github.com/netty/netty/issues/597 if (selectedKeys.isEmpty()) { return; } for (Iterator i = selectedKeys.iterator(); i.hasNext();) { SelectionKey k = i.next(); i.remove(); try { int readyOps = k.readyOps(); if ((readyOps & SelectionKey.OP_READ) != 0 || readyOps == 0) { if (!read(k)) { // Connection already closed - no need to handle write. continue; } } if ((readyOps & SelectionKey.OP_WRITE) != 0) { writeFromSelectorLoop(k); } } catch (CancelledKeyException e) { close(k); } if (cleanUpCancelledKeys()) { break; // break the loop to avoid ConcurrentModificationException } } } void writeFromUserCode(final AbstractNioChannel channel) { if (!channel.isConnected()) { cleanUpWriteBuffer(channel); return; } if (scheduleWriteIfNecessary(channel)) { return; } // From here, we are sure Thread.currentThread() == workerThread. if (channel.writeSuspended) { return; } if (channel.inWriteNowLoop) { return; } write0(channel); } void writeFromTaskLoop(AbstractNioChannel ch) { if (!ch.writeSuspended) { write0(ch); } } void writeFromSelectorLoop(final SelectionKey k) { AbstractNioChannel ch = (AbstractNioChannel) k.attachment(); ch.writeSuspended = false; write0(ch); } protected abstract boolean scheduleWriteIfNecessary(AbstractNioChannel channel); protected void write0(AbstractNioChannel channel) { boolean open = true; boolean addOpWrite = false; boolean removeOpWrite = false; boolean iothread = isIoThread(channel); long writtenBytes = 0; final SocketSendBufferPool sendBufferPool = this.sendBufferPool; final WritableByteChannel ch = channel.channel; final Queue writeBuffer = channel.writeBufferQueue; final int writeSpinCount = channel.getConfig().getWriteSpinCount(); List causes = null; synchronized (channel.writeLock) { channel.inWriteNowLoop = true; for (;;) { MessageEvent evt = channel.currentWriteEvent; SendBuffer buf = null; ChannelFuture future = null; try { if (evt == null) { if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) { removeOpWrite = true; channel.writeSuspended = false; break; } future = evt.getFuture(); channel.currentWriteBuffer = buf = sendBufferPool.acquire(evt.getMessage()); } else { future = evt.getFuture(); buf = channel.currentWriteBuffer; } long localWrittenBytes = 0; for (int i = writeSpinCount; i > 0; i --) { localWrittenBytes = buf.transferTo(ch); if (localWrittenBytes != 0) { writtenBytes += localWrittenBytes; break; } if (buf.finished()) { break; } } if (buf.finished()) { // Successful write - proceed to the next message. buf.release(); channel.currentWriteEvent = null; channel.currentWriteBuffer = null; // Mark the event object for garbage collection. //noinspection UnusedAssignment evt = null; buf = null; future.setSuccess(); } else { // Not written fully - perhaps the kernel buffer is full. addOpWrite = true; channel.writeSuspended = true; if (writtenBytes > 0) { // Notify progress listeners if necessary. future.setProgress( localWrittenBytes, buf.writtenBytes(), buf.totalBytes()); } break; } } catch (AsynchronousCloseException e) { // Doesn't need a user attention - ignore. } catch (Throwable t) { if (buf != null) { buf.release(); } channel.currentWriteEvent = null; channel.currentWriteBuffer = null; // Mark the event object for garbage collection. //noinspection UnusedAssignment buf = null; //noinspection UnusedAssignment evt = null; if (future != null) { future.setFailure(t); } if (iothread) { // An exception was thrown from within a write in the iothread. We store a reference to it // in a list for now and notify the handlers in the chain after the writeLock was released // to prevent possible deadlock. // See #1310 if (causes == null) { causes = new ArrayList(1); } causes.add(t); } else { fireExceptionCaughtLater(channel, t); } if (t instanceof IOException) { // close must be handled from outside the write lock to fix a possible deadlock // which can happen when MemoryAwareThreadPoolExecutor is used and the limit is exceed // and a close is triggered while the lock is hold. This is because the close(..) // may try to submit a task to handle it via the ExecutorHandler which then deadlocks. // See #1310 open = false; } } } channel.inWriteNowLoop = false; // Initially, the following block was executed after releasing // the writeLock, but there was a race condition, and it has to be // executed before releasing the writeLock: // // https://issues.jboss.org/browse/NETTY-410 // if (open) { if (addOpWrite) { setOpWrite(channel); } else if (removeOpWrite) { clearOpWrite(channel); } } } if (causes != null) { for (Throwable cause: causes) { // notify about cause now as it was triggered in the write loop fireExceptionCaught(channel, cause); } } if (!open) { // close the channel now close(channel, succeededFuture(channel)); } if (iothread) { fireWriteComplete(channel, writtenBytes); } else { fireWriteCompleteLater(channel, writtenBytes); } } static boolean isIoThread(AbstractNioChannel channel) { return Thread.currentThread() == channel.worker.thread; } protected void setOpWrite(AbstractNioChannel channel) { Selector selector = this.selector; SelectionKey key = channel.channel.keyFor(selector); if (key == null) { return; } if (!key.isValid()) { close(key); return; } int interestOps = channel.getRawInterestOps(); if ((interestOps & SelectionKey.OP_WRITE) == 0) { interestOps |= SelectionKey.OP_WRITE; key.interestOps(interestOps); channel.setRawInterestOpsNow(interestOps); } } protected void clearOpWrite(AbstractNioChannel channel) { Selector selector = this.selector; SelectionKey key = channel.channel.keyFor(selector); if (key == null) { return; } if (!key.isValid()) { close(key); return; } int interestOps = channel.getRawInterestOps(); if ((interestOps & SelectionKey.OP_WRITE) != 0) { interestOps &= ~SelectionKey.OP_WRITE; key.interestOps(interestOps); channel.setRawInterestOpsNow(interestOps); } } protected void close(AbstractNioChannel channel, ChannelFuture future) { boolean connected = channel.isConnected(); boolean bound = channel.isBound(); boolean iothread = isIoThread(channel); try { channel.channel.close(); increaseCancelledKeys(); if (channel.setClosed()) { future.setSuccess(); if (connected) { if (iothread) { fireChannelDisconnected(channel); } else { fireChannelDisconnectedLater(channel); } } if (bound) { if (iothread) { fireChannelUnbound(channel); } else { fireChannelUnboundLater(channel); } } cleanUpWriteBuffer(channel); if (iothread) { fireChannelClosed(channel); } else { fireChannelClosedLater(channel); } } else { future.setSuccess(); } } catch (Throwable t) { future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } protected static void cleanUpWriteBuffer(AbstractNioChannel channel) { Exception cause = null; boolean fireExceptionCaught = false; // Clean up the stale messages in the write buffer. synchronized (channel.writeLock) { MessageEvent evt = channel.currentWriteEvent; if (evt != null) { // Create the exception only once to avoid the excessive overhead // caused by fillStackTrace. if (channel.isOpen()) { cause = new NotYetConnectedException(); } else { cause = new ClosedChannelException(); } ChannelFuture future = evt.getFuture(); if (channel.currentWriteBuffer != null) { channel.currentWriteBuffer.release(); channel.currentWriteBuffer = null; } channel.currentWriteEvent = null; // Mark the event object for garbage collection. //noinspection UnusedAssignment evt = null; future.setFailure(cause); fireExceptionCaught = true; } Queue writeBuffer = channel.writeBufferQueue; for (;;) { evt = writeBuffer.poll(); if (evt == null) { break; } // Create the exception only once to avoid the excessive overhead // caused by fillStackTrace. if (cause == null) { if (channel.isOpen()) { cause = new NotYetConnectedException(); } else { cause = new ClosedChannelException(); } fireExceptionCaught = true; } evt.getFuture().setFailure(cause); } } if (fireExceptionCaught) { if (isIoThread(channel)) { fireExceptionCaught(channel, cause); } else { fireExceptionCaughtLater(channel, cause); } } } void setInterestOps(final AbstractNioChannel channel, final ChannelFuture future, final int interestOps) { boolean iothread = isIoThread(channel); if (!iothread) { channel.getPipeline().execute(new Runnable() { public void run() { setInterestOps(channel, future, interestOps); } }); return; } boolean changed = false; try { Selector selector = this.selector; SelectionKey key = channel.channel.keyFor(selector); // Override OP_WRITE flag - a user cannot change this flag. int newInterestOps = interestOps & ~Channel.OP_WRITE | channel.getRawInterestOps() & Channel.OP_WRITE; if (key == null || selector == null) { if (channel.getRawInterestOps() != newInterestOps) { changed = true; } // Not registered to the worker yet. // Set the rawInterestOps immediately; RegisterTask will pick it up. channel.setRawInterestOpsNow(newInterestOps); future.setSuccess(); if (changed) { if (iothread) { fireChannelInterestChanged(channel); } else { fireChannelInterestChangedLater(channel); } } return; } if (channel.getRawInterestOps() != newInterestOps) { key.interestOps(newInterestOps); if (Thread.currentThread() != thread && wakenUp.compareAndSet(false, true)) { selector.wakeup(); } channel.setRawInterestOpsNow(newInterestOps); } future.setSuccess(); if (changed) { fireChannelInterestChanged(channel); } } catch (CancelledKeyException e) { // setInterestOps() was called on a closed channel. ClosedChannelException cce = new ClosedChannelException(); future.setFailure(cce); fireExceptionCaught(channel, cce); } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } /** * Read is called when a Selector has been notified that the underlying channel * was something to be read. The channel would previously have registered its interest * in read operations. * * @param k The selection key which contains the Selector registration information. */ protected abstract boolean read(SelectionKey k); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/AbstractNioWorkerPool.java000066400000000000000000000133201225554127700333630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.socket.Worker; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.internal.ExecutorUtil; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * Abstract base class for {@link WorkerPool} implementations that create the {@link Worker}'s * up-front and return them in a "fair" fashion when calling {@link #nextWorker()} */ public abstract class AbstractNioWorkerPool implements WorkerPool, ExternalResourceReleasable { /** * The worker pool raises an exception unless all worker threads start and run within this timeout (in seconds.) */ private static final int INITIALIZATION_TIMEOUT = 10; private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractNioWorkerPool.class); private final AbstractNioWorker[] workers; private final AtomicInteger workerIndex = new AtomicInteger(); private final Executor workerExecutor; private volatile boolean initialized; /** * Create a new instance * * @param workerExecutor the {@link Executor} to use for the {@link Worker}'s * @param workerCount the count of {@link Worker}'s to create */ AbstractNioWorkerPool(Executor workerExecutor, int workerCount) { this(workerExecutor, workerCount, true); } AbstractNioWorkerPool(Executor workerExecutor, int workerCount, boolean autoInit) { if (workerExecutor == null) { throw new NullPointerException("workerExecutor"); } if (workerCount <= 0) { throw new IllegalArgumentException( "workerCount (" + workerCount + ") " + "must be a positive integer."); } workers = new AbstractNioWorker[workerCount]; this.workerExecutor = workerExecutor; if (autoInit) { init(); } } protected void init() { if (initialized) { throw new IllegalStateException("initialized already"); } initialized = true; for (int i = 0; i < workers.length; i++) { workers[i] = newWorker(workerExecutor); } waitForWorkerThreads(); } private void waitForWorkerThreads() { long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(INITIALIZATION_TIMEOUT); boolean warn = false; for (AbstractNioSelector worker: workers) { long waitTime = deadline - System.nanoTime(); try { if (waitTime <= 0) { if (worker.thread == null) { warn = true; break; } } else if (!worker.startupLatch.await(waitTime, TimeUnit.NANOSECONDS)) { warn = true; break; } } catch (InterruptedException ignore) { // Stop waiting for the worker threads and let someone else take care of the interruption. Thread.currentThread().interrupt(); break; } } if (warn) { logger.warn( "Failed to get all worker threads ready within " + INITIALIZATION_TIMEOUT + " second(s). " + "Make sure to specify the executor which has more threads than the requested workerCount. " + "If unsure, use Executors.newCachedThreadPool()."); } } /** * Only here for backward compability and will be removed in later releases. Please use * {@link #newWorker(Executor)} * * * @param executor the {@link Executor} to use * @return worker the new {@link Worker} * @deprecated use {@link #newWorker(Executor)} */ @Deprecated protected E createWorker(Executor executor) { throw new IllegalStateException("This will be removed. Override this and the newWorker(..) method!"); } /** * Create a new {@link Worker} which uses the given {@link Executor} to service IO. * * This method will be made abstract in further releases (once {@link #createWorker(Executor)} * was removed). * * * @param executor the {@link Executor} to use * @return worker the new {@link Worker} */ @SuppressWarnings("deprecation") protected E newWorker(Executor executor) { return createWorker(executor); } @SuppressWarnings("unchecked") public E nextWorker() { return (E) workers[Math.abs(workerIndex.getAndIncrement() % workers.length)]; } public void rebuildSelectors() { for (AbstractNioWorker worker: workers) { worker.rebuildSelector(); } } public void releaseExternalResources() { shutdown(); ExecutorUtil.shutdownNow(workerExecutor); } public void shutdown() { for (AbstractNioWorker worker: workers) { worker.shutdown(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/Boss.java000066400000000000000000000014211225554127700300330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; /** * Serves the boss tasks like connecting/accepting */ public interface Boss extends NioSelector { } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/BossPool.java000066400000000000000000000015661225554127700306770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; /** * A Pool that holds {@link Boss} instances */ public interface BossPool extends NioSelectorPool { /** * Return the next {@link Boss} to use * */ E nextBoss(); } DefaultNioDatagramChannelConfig.java000066400000000000000000000206221225554127700351640ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.StandardSocketOptions; import java.nio.channels.DatagramChannel; import java.util.Enumeration; import java.util.Map; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.socket.DefaultDatagramChannelConfig; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.ConversionUtil; import org.jboss.netty.util.internal.DetectionUtil; /** * The default {@link NioSocketChannelConfig} implementation. */ class DefaultNioDatagramChannelConfig extends DefaultDatagramChannelConfig implements NioDatagramChannelConfig { private static final InternalLogger logger = InternalLoggerFactory .getInstance(DefaultNioDatagramChannelConfig.class); private volatile int writeBufferHighWaterMark = 64 * 1024; private volatile int writeBufferLowWaterMark = 32 * 1024; private volatile int writeSpinCount = 16; private final DatagramChannel channel; DefaultNioDatagramChannelConfig(DatagramChannel channel) { super(channel.socket()); this.channel = channel; } @Override public void setOptions(Map options) { super.setOptions(options); if (getWriteBufferHighWaterMark() < getWriteBufferLowWaterMark()) { // Recover the integrity of the configuration with a sensible value. setWriteBufferLowWaterMark0(getWriteBufferHighWaterMark() >>> 1); if (logger.isWarnEnabled()) { // Notify the user about misconfiguration. logger.warn("writeBufferLowWaterMark cannot be greater than " + "writeBufferHighWaterMark; setting to the half of the " + "writeBufferHighWaterMark."); } } } @Override public boolean setOption(String key, Object value) { if (super.setOption(key, value)) { return true; } if ("writeBufferHighWaterMark".equals(key)) { setWriteBufferHighWaterMark0(ConversionUtil.toInt(value)); } else if ("writeBufferLowWaterMark".equals(key)) { setWriteBufferLowWaterMark0(ConversionUtil.toInt(value)); } else if ("writeSpinCount".equals(key)) { setWriteSpinCount(ConversionUtil.toInt(value)); } else { return false; } return true; } public int getWriteBufferHighWaterMark() { return writeBufferHighWaterMark; } public void setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { if (writeBufferHighWaterMark < getWriteBufferLowWaterMark()) { throw new IllegalArgumentException( "writeBufferHighWaterMark cannot be less than " + "writeBufferLowWaterMark (" + getWriteBufferLowWaterMark() + "): " + writeBufferHighWaterMark); } setWriteBufferHighWaterMark0(writeBufferHighWaterMark); } private void setWriteBufferHighWaterMark0(int writeBufferHighWaterMark) { if (writeBufferHighWaterMark < 0) { throw new IllegalArgumentException("writeBufferHighWaterMark: " + writeBufferHighWaterMark); } this.writeBufferHighWaterMark = writeBufferHighWaterMark; } public int getWriteBufferLowWaterMark() { return writeBufferLowWaterMark; } public void setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { if (writeBufferLowWaterMark > getWriteBufferHighWaterMark()) { throw new IllegalArgumentException( "writeBufferLowWaterMark cannot be greater than " + "writeBufferHighWaterMark (" + getWriteBufferHighWaterMark() + "): " + writeBufferLowWaterMark); } setWriteBufferLowWaterMark0(writeBufferLowWaterMark); } private void setWriteBufferLowWaterMark0(int writeBufferLowWaterMark) { if (writeBufferLowWaterMark < 0) { throw new IllegalArgumentException("writeBufferLowWaterMark: " + writeBufferLowWaterMark); } this.writeBufferLowWaterMark = writeBufferLowWaterMark; } public int getWriteSpinCount() { return writeSpinCount; } public void setWriteSpinCount(int writeSpinCount) { if (writeSpinCount <= 0) { throw new IllegalArgumentException( "writeSpinCount must be a positive integer."); } this.writeSpinCount = writeSpinCount; } @Override public void setNetworkInterface(NetworkInterface networkInterface) { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { try { channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface); } catch (IOException e) { throw new ChannelException(e); } } } @Override public NetworkInterface getNetworkInterface() { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { try { return channel.getOption(StandardSocketOptions.IP_MULTICAST_IF); } catch (IOException e) { throw new ChannelException(e); } } } @Override public int getTimeToLive() { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { try { return channel.getOption(StandardSocketOptions.IP_MULTICAST_TTL); } catch (IOException e) { throw new ChannelException(e); } } } @Override public void setTimeToLive(int ttl) { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { try { channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl); } catch (IOException e) { throw new ChannelException(e); } } } @Override public InetAddress getInterface() { NetworkInterface inf = getNetworkInterface(); if (inf == null) { return null; } else { Enumeration addresses = inf.getInetAddresses(); if (addresses.hasMoreElements()) { return addresses.nextElement(); } return null; } } @Override public void setInterface(InetAddress interfaceAddress) { try { setNetworkInterface(NetworkInterface.getByInetAddress(interfaceAddress)); } catch (SocketException e) { throw new ChannelException(e); } } @Override public boolean isLoopbackModeDisabled() { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { try { return channel.getOption(StandardSocketOptions.IP_MULTICAST_LOOP); } catch (IOException e) { throw new ChannelException(e); } } } @Override public void setLoopbackModeDisabled(boolean loopbackModeDisabled) { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { try { channel.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, loopbackModeDisabled); } catch (IOException e) { throw new ChannelException(e); } } } } DefaultNioSocketChannelConfig.java000066400000000000000000000156341225554127700347030ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.net.Socket; import java.util.Map; import org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import org.jboss.netty.channel.ReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.socket.DefaultSocketChannelConfig; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.ConversionUtil; /** * The default {@link NioSocketChannelConfig} implementation. */ class DefaultNioSocketChannelConfig extends DefaultSocketChannelConfig implements NioSocketChannelConfig { private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultNioSocketChannelConfig.class); private static final ReceiveBufferSizePredictorFactory DEFAULT_PREDICTOR_FACTORY = new AdaptiveReceiveBufferSizePredictorFactory(); private volatile int writeBufferHighWaterMark = 64 * 1024; private volatile int writeBufferLowWaterMark = 32 * 1024; private volatile ReceiveBufferSizePredictor predictor; private volatile ReceiveBufferSizePredictorFactory predictorFactory = DEFAULT_PREDICTOR_FACTORY; private volatile int writeSpinCount = 16; DefaultNioSocketChannelConfig(Socket socket) { super(socket); } @Override public void setOptions(Map options) { super.setOptions(options); if (getWriteBufferHighWaterMark() < getWriteBufferLowWaterMark()) { // Recover the integrity of the configuration with a sensible value. setWriteBufferLowWaterMark0(getWriteBufferHighWaterMark() >>> 1); if (logger.isWarnEnabled()) { // Notify the user about misconfiguration. logger.warn( "writeBufferLowWaterMark cannot be greater than " + "writeBufferHighWaterMark; setting to the half of the " + "writeBufferHighWaterMark."); } } } @Override public boolean setOption(String key, Object value) { if (super.setOption(key, value)) { return true; } if ("writeBufferHighWaterMark".equals(key)) { setWriteBufferHighWaterMark0(ConversionUtil.toInt(value)); } else if ("writeBufferLowWaterMark".equals(key)) { setWriteBufferLowWaterMark0(ConversionUtil.toInt(value)); } else if ("writeSpinCount".equals(key)) { setWriteSpinCount(ConversionUtil.toInt(value)); } else if ("receiveBufferSizePredictorFactory".equals(key)) { setReceiveBufferSizePredictorFactory((ReceiveBufferSizePredictorFactory) value); } else if ("receiveBufferSizePredictor".equals(key)) { setReceiveBufferSizePredictor((ReceiveBufferSizePredictor) value); } else { return false; } return true; } public int getWriteBufferHighWaterMark() { return writeBufferHighWaterMark; } public void setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { if (writeBufferHighWaterMark < getWriteBufferLowWaterMark()) { throw new IllegalArgumentException( "writeBufferHighWaterMark cannot be less than " + "writeBufferLowWaterMark (" + getWriteBufferLowWaterMark() + "): " + writeBufferHighWaterMark); } setWriteBufferHighWaterMark0(writeBufferHighWaterMark); } private void setWriteBufferHighWaterMark0(int writeBufferHighWaterMark) { if (writeBufferHighWaterMark < 0) { throw new IllegalArgumentException( "writeBufferHighWaterMark: " + writeBufferHighWaterMark); } this.writeBufferHighWaterMark = writeBufferHighWaterMark; } public int getWriteBufferLowWaterMark() { return writeBufferLowWaterMark; } public void setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { if (writeBufferLowWaterMark > getWriteBufferHighWaterMark()) { throw new IllegalArgumentException( "writeBufferLowWaterMark cannot be greater than " + "writeBufferHighWaterMark (" + getWriteBufferHighWaterMark() + "): " + writeBufferLowWaterMark); } setWriteBufferLowWaterMark0(writeBufferLowWaterMark); } private void setWriteBufferLowWaterMark0(int writeBufferLowWaterMark) { if (writeBufferLowWaterMark < 0) { throw new IllegalArgumentException( "writeBufferLowWaterMark: " + writeBufferLowWaterMark); } this.writeBufferLowWaterMark = writeBufferLowWaterMark; } public int getWriteSpinCount() { return writeSpinCount; } public void setWriteSpinCount(int writeSpinCount) { if (writeSpinCount <= 0) { throw new IllegalArgumentException( "writeSpinCount must be a positive integer."); } this.writeSpinCount = writeSpinCount; } public ReceiveBufferSizePredictor getReceiveBufferSizePredictor() { ReceiveBufferSizePredictor predictor = this.predictor; if (predictor == null) { try { this.predictor = predictor = getReceiveBufferSizePredictorFactory().getPredictor(); } catch (Exception e) { throw new ChannelException( "Failed to create a new " + ReceiveBufferSizePredictor.class.getSimpleName() + '.', e); } } return predictor; } public void setReceiveBufferSizePredictor( ReceiveBufferSizePredictor predictor) { if (predictor == null) { throw new NullPointerException("predictor"); } this.predictor = predictor; } public ReceiveBufferSizePredictorFactory getReceiveBufferSizePredictorFactory() { return predictorFactory; } public void setReceiveBufferSizePredictorFactory(ReceiveBufferSizePredictorFactory predictorFactory) { if (predictorFactory == null) { throw new NullPointerException("predictorFactory"); } this.predictorFactory = predictorFactory; } } NioAcceptedSocketChannel.java000066400000000000000000000026231225554127700336730ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import static org.jboss.netty.channel.Channels.*; import java.nio.channels.SocketChannel; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; final class NioAcceptedSocketChannel extends NioSocketChannel { final Thread bossThread; NioAcceptedSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, Channel parent, ChannelSink sink, SocketChannel socket, NioWorker worker, Thread bossThread) { super(parent, factory, pipeline, sink, socket, worker); this.bossThread = bossThread; setConnected(); fireChannelOpen(this); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioChannelConfig.java000066400000000000000000000063511225554127700323000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelConfig; /** * Special {@link ChannelConfig} sub-type which offers extra methods which are useful for NIO. * */ public interface NioChannelConfig extends ChannelConfig { /** * Returns the high water mark of the write buffer. If the number of bytes * queued in the write buffer exceeds this value, {@link Channel#isWritable()} * will start to return {@code false}. */ int getWriteBufferHighWaterMark(); /** * Sets the high water mark of the write buffer. If the number of bytes * queued in the write buffer exceeds this value, {@link Channel#isWritable()} * will start to return {@code false}. */ void setWriteBufferHighWaterMark(int writeBufferHighWaterMark); /** * Returns the low water mark of the write buffer. Once the number of bytes * queued in the write buffer exceeded the * {@linkplain #setWriteBufferHighWaterMark(int) high water mark} and then * dropped down below this value, {@link Channel#isWritable()} will start to return * {@code true} again. */ int getWriteBufferLowWaterMark(); /** * Sets the low water mark of the write buffer. Once the number of bytes * queued in the write buffer exceeded the * {@linkplain #setWriteBufferHighWaterMark(int) high water mark} and then * dropped down below this value, {@link Channel#isWritable()} will start toreturn * {@code true} again. */ void setWriteBufferLowWaterMark(int writeBufferLowWaterMark); /** * Returns the maximum loop count for a write operation until * {@link WritableByteChannel#write(ByteBuffer)} returns a non-zero value. * It is similar to what a spin lock is used for in concurrency programming. * It improves memory utilization and write throughput depending on * the platform that JVM runs on. The default value is {@code 16}. */ int getWriteSpinCount(); /** * Sets the maximum loop count for a write operation until * {@link WritableByteChannel#write(ByteBuffer)} returns a non-zero value. * It is similar to what a spin lock is used for in concurrency programming. * It improves memory utilization and write throughput depending on * the platform that JVM runs on. The default value is {@code 16}. * * @throws IllegalArgumentException * if the specified value is {@code 0} or less than {@code 0} */ void setWriteSpinCount(int writeSpinCount); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioClientBoss.java000066400000000000000000000162211225554127700316440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ConnectTimeoutException; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import java.io.IOException; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.Iterator; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import static org.jboss.netty.channel.Channels.*; /** * {@link Boss} implementation that handles the connection attempts of clients */ public final class NioClientBoss extends AbstractNioSelector implements Boss { private final TimerTask wakeupTask = new TimerTask() { public void run(Timeout timeout) throws Exception { // This is needed to prevent a possible race that can lead to a NPE // when the selector is closed before this is run // // See https://github.com/netty/netty/issues/685 Selector selector = NioClientBoss.this.selector; if (selector != null) { if (wakenUp.compareAndSet(false, true)) { selector.wakeup(); } } } }; private final Timer timer; NioClientBoss(Executor bossExecutor, Timer timer, ThreadNameDeterminer determiner) { super(bossExecutor, determiner); this.timer = timer; } @Override protected ThreadRenamingRunnable newThreadRenamingRunnable(int id, ThreadNameDeterminer determiner) { return new ThreadRenamingRunnable(this, "New I/O boss #" + id, determiner); } @Override protected Runnable createRegisterTask(Channel channel, ChannelFuture future) { return new RegisterTask(this, (NioClientSocketChannel) channel); } @Override protected void process(Selector selector) { processSelectedKeys(selector.selectedKeys()); // Handle connection timeout every 10 milliseconds approximately. long currentTimeNanos = System.nanoTime(); processConnectTimeout(selector.keys(), currentTimeNanos); } private void processSelectedKeys(Set selectedKeys) { // check if the set is empty and if so just return to not create garbage by // creating a new Iterator every time even if there is nothing to process. // See https://github.com/netty/netty/issues/597 if (selectedKeys.isEmpty()) { return; } for (Iterator i = selectedKeys.iterator(); i.hasNext();) { SelectionKey k = i.next(); i.remove(); if (!k.isValid()) { close(k); continue; } try { if (k.isConnectable()) { connect(k); } } catch (Throwable t) { NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment(); ch.connectFuture.setFailure(t); fireExceptionCaught(ch, t); k.cancel(); // Some JDK implementations run into an infinite loop without this. ch.worker.close(ch, succeededFuture(ch)); } } } private static void processConnectTimeout(Set keys, long currentTimeNanos) { ConnectException cause = null; for (SelectionKey k: keys) { if (!k.isValid()) { // Comment the close call again as it gave us major problems // with ClosedChannelExceptions. // // See: // * https://github.com/netty/netty/issues/142 // * https://github.com/netty/netty/issues/138 // // close(k); continue; } NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment(); if (ch.connectDeadlineNanos > 0 && currentTimeNanos >= ch.connectDeadlineNanos) { if (cause == null) { cause = new ConnectTimeoutException("connection timed out: " + ch.requestedRemoteAddress); } ch.connectFuture.setFailure(cause); fireExceptionCaught(ch, cause); ch.worker.close(ch, succeededFuture(ch)); } } } private static void connect(SelectionKey k) throws IOException { NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment(); try { if (ch.channel.finishConnect()) { k.cancel(); if (ch.timoutTimer != null) { ch.timoutTimer.cancel(); } ch.worker.register(ch, ch.connectFuture); } } catch (ConnectException e) { ConnectException newE = new ConnectException(e.getMessage() + ": " + ch.requestedRemoteAddress); newE.setStackTrace(e.getStackTrace()); throw newE; } } @Override protected void close(SelectionKey k) { NioClientSocketChannel ch = (NioClientSocketChannel) k.attachment(); ch.worker.close(ch, succeededFuture(ch)); } private final class RegisterTask implements Runnable { private final NioClientBoss boss; private final NioClientSocketChannel channel; RegisterTask(NioClientBoss boss, NioClientSocketChannel channel) { this.boss = boss; this.channel = channel; } public void run() { int timeout = channel.getConfig().getConnectTimeoutMillis(); if (timeout > 0) { if (!channel.isConnected()) { channel.timoutTimer = timer.newTimeout(wakeupTask, timeout, TimeUnit.MILLISECONDS); } } try { channel.channel.register( boss.selector, SelectionKey.OP_CONNECT, channel); } catch (ClosedChannelException e) { channel.worker.close(channel, succeededFuture(channel)); } int connectTimeout = channel.getConfig().getConnectTimeoutMillis(); if (connectTimeout > 0) { channel.connectDeadlineNanos = System.nanoTime() + connectTimeout * 1000000L; } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioClientBossPool.java000066400000000000000000000052731225554127700325030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.Timer; import java.util.concurrent.Executor; /** * Holds {@link NioClientBoss} instances to use */ public class NioClientBossPool extends AbstractNioBossPool { private final ThreadNameDeterminer determiner; private final Timer timer; private boolean stopTimer; /** * Create a new instance * * @param bossExecutor the Executor to use for server the {@link NioClientBoss} * @param bossCount the number of {@link NioClientBoss} instances this {@link NioClientBossPool} will hold * @param timer the Timer to use for handle connect timeouts * @param determiner the {@link ThreadNameDeterminer} to use for name the threads. Use {@code null} * if you not want to set one explicit. */ public NioClientBossPool(Executor bossExecutor, int bossCount, Timer timer, ThreadNameDeterminer determiner) { super(bossExecutor, bossCount, false); this.determiner = determiner; this.timer = timer; init(); } /** * Create a new instance using a new {@link HashedWheelTimer} and no {@link ThreadNameDeterminer} * * @param bossExecutor the Executor to use for server the {@link NioClientBoss} * @param bossCount the number of {@link NioClientBoss} instances this {@link NioClientBoss} will hold */ public NioClientBossPool(Executor bossExecutor, int bossCount) { this(bossExecutor, bossCount, new HashedWheelTimer(), null); stopTimer = true; } @Override protected NioClientBoss newBoss(Executor executor) { return new NioClientBoss(executor, timer, determiner); } @Override public void shutdown() { super.shutdown(); if (stopTimer) { timer.stop(); } } @Override public void releaseExternalResources() { super.releaseExternalResources(); timer.stop(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioClientSocketChannel.java000066400000000000000000000054311225554127700334600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.Timeout; import java.io.IOException; import java.net.SocketAddress; import java.nio.channels.SocketChannel; import static org.jboss.netty.channel.Channels.*; final class NioClientSocketChannel extends NioSocketChannel { private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioClientSocketChannel.class); private static SocketChannel newSocket() { SocketChannel socket; try { socket = SocketChannel.open(); } catch (IOException e) { throw new ChannelException("Failed to open a socket.", e); } boolean success = false; try { socket.configureBlocking(false); success = true; } catch (IOException e) { throw new ChannelException("Failed to enter non-blocking mode.", e); } finally { if (!success) { try { socket.close(); } catch (IOException e) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e); } } } } return socket; } volatile ChannelFuture connectFuture; volatile boolean boundManually; // Does not need to be volatile as it's accessed by only one thread. long connectDeadlineNanos; volatile SocketAddress requestedRemoteAddress; volatile Timeout timoutTimer; NioClientSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, NioWorker worker) { super(null, factory, pipeline, sink, newSocket(), worker); fireChannelOpen(this); } } NioClientSocketChannelFactory.java000066400000000000000000000214771225554127700347410ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.nio.channels.Selector; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.Timer; /** * A {@link ClientSocketChannelFactory} which creates a client-side NIO-based * {@link SocketChannel}. It utilizes the non-blocking I/O mode which was * introduced with NIO to serve many number of concurrent connections * efficiently. * *

How threads work

*

* There are two types of threads in a {@link NioClientSocketChannelFactory}; * one is boss thread and the other is worker thread. * *

Boss thread

*

* One {@link NioClientSocketChannelFactory} has one boss thread. It makes * a connection attempt on request. Once a connection attempt succeeds, * the boss thread passes the connected {@link Channel} to one of the worker * threads that the {@link NioClientSocketChannelFactory} manages. * *

Worker threads

*

* One {@link NioClientSocketChannelFactory} can have one or more worker * threads. A worker thread performs non-blocking read and write for one or * more {@link Channel}s in a non-blocking mode. * *

Life cycle of threads and graceful shutdown

*

* All threads are acquired from the {@link Executor}s which were specified * when a {@link NioClientSocketChannelFactory} was created. A boss thread is * acquired from the {@code bossExecutor}, and worker threads are acquired from * the {@code workerExecutor}. Therefore, you should make sure the specified * {@link Executor}s are able to lend the sufficient number of threads. * It is the best bet to specify {@linkplain Executors#newCachedThreadPool() a cached thread pool}. *

* Both boss and worker threads are acquired lazily, and then released when * there's nothing left to process. All the related resources such as * {@link Selector} are also released when the boss and worker threads are * released. Therefore, to shut down a service gracefully, you should do the * following: * *

    *
  1. close all channels created by the factory usually using * {@link ChannelGroup#close()}, and
  2. *
  3. call {@link #releaseExternalResources()}.
  4. *
* * Please make sure not to shut down the executor until all channels are * closed. Otherwise, you will end up with a {@link RejectedExecutionException} * and the related resources might not be released properly. * * @apiviz.landmark */ public class NioClientSocketChannelFactory implements ClientSocketChannelFactory { private static final int DEFAULT_BOSS_COUNT = 1; private final BossPool bossPool; private final WorkerPool workerPool; private final NioClientSocketPipelineSink sink; private boolean releasePools; /** * Creates a new {@link NioClientSocketChannelFactory} which uses {@link Executors#newCachedThreadPool()} * for the worker and boss executors. * * See {@link #NioClientSocketChannelFactory(Executor, Executor)} */ public NioClientSocketChannelFactory() { this(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); releasePools = true; } /** * Creates a new instance. Calling this constructor is same with calling * {@link #NioClientSocketChannelFactory(Executor, Executor, int, int)} with * 1 and (2 * the number of available processors in the machine) for * bossCount and workerCount respectively. The number of * available processors is obtained by {@link Runtime#availableProcessors()}. * * @param bossExecutor * the {@link Executor} which will execute the boss thread * @param workerExecutor * the {@link Executor} which will execute the worker threads */ public NioClientSocketChannelFactory( Executor bossExecutor, Executor workerExecutor) { this(bossExecutor, workerExecutor, DEFAULT_BOSS_COUNT, SelectorUtil.DEFAULT_IO_THREADS); } /** * Creates a new instance. Calling this constructor is same with calling * {@link #NioClientSocketChannelFactory(Executor, Executor, int, int)} with * 1 as bossCount. * * @param bossExecutor * the {@link Executor} which will execute the boss thread * @param workerExecutor * the {@link Executor} which will execute the worker threads * @param workerCount * the maximum number of I/O worker threads */ public NioClientSocketChannelFactory( Executor bossExecutor, Executor workerExecutor, int workerCount) { this(bossExecutor, workerExecutor, DEFAULT_BOSS_COUNT, workerCount); } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss thread * @param workerExecutor * the {@link Executor} which will execute the worker threads * @param bossCount * the maximum number of boss threads * @param workerCount * the maximum number of I/O worker threads */ public NioClientSocketChannelFactory( Executor bossExecutor, Executor workerExecutor, int bossCount, int workerCount) { this(bossExecutor, bossCount, new NioWorkerPool(workerExecutor, workerCount)); } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss thread * @param bossCount * the maximum number of boss threads * @param workerPool * the {@link WorkerPool} to use to do the IO */ public NioClientSocketChannelFactory( Executor bossExecutor, int bossCount, WorkerPool workerPool) { this(new NioClientBossPool(bossExecutor, bossCount), workerPool); } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss thread * @param bossCount * the maximum number of boss threads * @param workerPool * the {@link WorkerPool} to use to do the IO * @param timer * the {@link Timer} to use to handle the connection timeouts */ public NioClientSocketChannelFactory( Executor bossExecutor, int bossCount, WorkerPool workerPool, Timer timer) { this(new NioClientBossPool(bossExecutor, bossCount, timer, null), workerPool); } /** * Creates a new instance. * * @param bossPool * the {@link BossPool} to use to handle the connects * @param workerPool * the {@link WorkerPool} to use to do the IO */ public NioClientSocketChannelFactory( BossPool bossPool, WorkerPool workerPool) { if (bossPool == null) { throw new NullPointerException("bossPool"); } if (workerPool == null) { throw new NullPointerException("workerPool"); } this.bossPool = bossPool; this.workerPool = workerPool; sink = new NioClientSocketPipelineSink(bossPool); } public SocketChannel newChannel(ChannelPipeline pipeline) { return new NioClientSocketChannel(this, pipeline, sink, workerPool.nextWorker()); } public void shutdown() { bossPool.shutdown(); workerPool.shutdown(); if (releasePools) { releasePools(); } } public void releaseExternalResources() { shutdown(); releasePools(); } private void releasePools() { if (bossPool instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) bossPool).releaseExternalResources(); } if (workerPool instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) workerPool).releaseExternalResources(); } } } NioClientSocketPipelineSink.java000066400000000000000000000122031225554127700344160ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.net.ConnectException; import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; import static org.jboss.netty.channel.Channels.*; class NioClientSocketPipelineSink extends AbstractNioChannelSink { static final InternalLogger logger = InternalLoggerFactory.getInstance(NioClientSocketPipelineSink.class); private final BossPool bossPool; NioClientSocketPipelineSink(BossPool bossPool) { this.bossPool = bossPool; } public void eventSunk( ChannelPipeline pipeline, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { ChannelStateEvent event = (ChannelStateEvent) e; NioClientSocketChannel channel = (NioClientSocketChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { channel.worker.close(channel, future); } break; case BOUND: if (value != null) { bind(channel, future, (SocketAddress) value); } else { channel.worker.close(channel, future); } break; case CONNECTED: if (value != null) { connect(channel, future, (SocketAddress) value); } else { channel.worker.close(channel, future); } break; case INTEREST_OPS: channel.worker.setInterestOps(channel, future, ((Integer) value).intValue()); break; } } else if (e instanceof MessageEvent) { MessageEvent event = (MessageEvent) e; NioSocketChannel channel = (NioSocketChannel) event.getChannel(); boolean offered = channel.writeBufferQueue.offer(event); assert offered; channel.worker.writeFromUserCode(channel); } } private static void bind( NioClientSocketChannel channel, ChannelFuture future, SocketAddress localAddress) { try { channel.channel.socket().bind(localAddress); channel.boundManually = true; channel.setBound(); future.setSuccess(); fireChannelBound(channel, channel.getLocalAddress()); } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } private void connect( final NioClientSocketChannel channel, final ChannelFuture cf, SocketAddress remoteAddress) { channel.requestedRemoteAddress = remoteAddress; try { if (channel.channel.connect(remoteAddress)) { channel.worker.register(channel, cf); } else { channel.getCloseFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) throws Exception { if (!cf.isDone()) { cf.setFailure(new ClosedChannelException()); } } }); cf.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); channel.connectFuture = cf; nextBoss().register(channel, cf); } } catch (Throwable t) { if (t instanceof ConnectException) { Throwable newT = new ConnectException(t.getMessage() + ": " + remoteAddress); newT.setStackTrace(t.getStackTrace()); t = newT; } cf.setFailure(t); fireExceptionCaught(channel, t); channel.worker.close(channel, succeededFuture(channel)); } } private NioClientBoss nextBoss() { return bossPool.nextBoss(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramChannel.java000066400000000000000000000252511225554127700326130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.socket.DatagramChannelConfig; import org.jboss.netty.channel.socket.InternetProtocolFamily; import org.jboss.netty.util.internal.DetectionUtil; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.DatagramChannel; import java.nio.channels.MembershipKey; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import static org.jboss.netty.channel.Channels.*; /** * Provides an NIO based {@link org.jboss.netty.channel.socket.DatagramChannel}. */ public class NioDatagramChannel extends AbstractNioChannel implements org.jboss.netty.channel.socket.DatagramChannel { /** * The {@link DatagramChannelConfig}. */ private final NioDatagramChannelConfig config; private Map> memberships; NioDatagramChannel(final ChannelFactory factory, final ChannelPipeline pipeline, final ChannelSink sink, final NioDatagramWorker worker, InternetProtocolFamily family) { super(null, factory, pipeline, sink, worker, openNonBlockingChannel(family)); config = new DefaultNioDatagramChannelConfig(channel); fireChannelOpen(this); } private static DatagramChannel openNonBlockingChannel(InternetProtocolFamily family) { try { final DatagramChannel channel; // check if we are on java 7 or if the family was not specified if (DetectionUtil.javaVersion() < 7 || family == null) { channel = DatagramChannel.open(); } else { // This block only works on java7++, but we checked before if we have it. // // Use the ProtocolFamilyConvert for conversion to prevent NoClassDefFoundError. // // See #368 switch (family) { case IPv4: channel = DatagramChannel.open(ProtocolFamilyConverter.convert(family)); break; case IPv6: channel = DatagramChannel.open(ProtocolFamilyConverter.convert(family)); break; default: throw new IllegalArgumentException(); } } channel.configureBlocking(false); return channel; } catch (final IOException e) { throw new ChannelException("Failed to open a DatagramChannel.", e); } } @Override public NioDatagramWorker getWorker() { return (NioDatagramWorker) super.getWorker(); } public boolean isBound() { return isOpen() && channel.socket().isBound(); } public boolean isConnected() { return channel.isConnected(); } @Override protected boolean setClosed() { return super.setClosed(); } @Override public NioDatagramChannelConfig getConfig() { return config; } DatagramChannel getDatagramChannel() { return channel; } public ChannelFuture joinGroup(InetAddress multicastAddress) { try { return joinGroup( multicastAddress, NetworkInterface.getByInetAddress(getLocalAddress().getAddress()), null); } catch (SocketException e) { return failedFuture(this, e); } } public ChannelFuture joinGroup(InetSocketAddress multicastAddress, NetworkInterface networkInterface) { return joinGroup(multicastAddress.getAddress(), networkInterface, null); } /** * Joins the specified multicast group at the specified interface using the specified source. */ public ChannelFuture joinGroup( InetAddress multicastAddress, NetworkInterface networkInterface, InetAddress source) { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } if (multicastAddress == null) { throw new NullPointerException("multicastAddress"); } if (networkInterface == null) { throw new NullPointerException("networkInterface"); } try { MembershipKey key; if (source == null) { key = channel.join(multicastAddress, networkInterface); } else { key = channel.join(multicastAddress, networkInterface, source); } synchronized (this) { if (memberships == null) { memberships = new HashMap>(); } List keys = memberships.get(multicastAddress); if (keys == null) { keys = new ArrayList(); memberships.put(multicastAddress, keys); } keys.add(key); } } catch (Throwable e) { return failedFuture(this, e); } return succeededFuture(this); } public ChannelFuture leaveGroup(InetAddress multicastAddress) { try { return leaveGroup( multicastAddress, NetworkInterface.getByInetAddress(getLocalAddress().getAddress()), null); } catch (SocketException e) { return failedFuture(this, e); } } public ChannelFuture leaveGroup(InetSocketAddress multicastAddress, NetworkInterface networkInterface) { return leaveGroup(multicastAddress.getAddress(), networkInterface, null); } /** * Leave the specified multicast group at the specified interface using the specified source. */ public ChannelFuture leaveGroup(InetAddress multicastAddress, NetworkInterface networkInterface, InetAddress source) { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { if (multicastAddress == null) { throw new NullPointerException("multicastAddress"); } if (networkInterface == null) { throw new NullPointerException("networkInterface"); } synchronized (this) { if (memberships != null) { List keys = memberships.get(multicastAddress); if (keys != null) { Iterator keyIt = keys.iterator(); while (keyIt.hasNext()) { MembershipKey key = keyIt.next(); if (networkInterface.equals(key.networkInterface())) { if (source == null && key.sourceAddress() == null || source != null && source.equals(key.sourceAddress())) { key.drop(); keyIt.remove(); } } } if (keys.isEmpty()) { memberships.remove(multicastAddress); } } } } return succeededFuture(this); } } /** * Block the given sourceToBlock address for the given multicastAddress on the given networkInterface * */ public ChannelFuture block(InetAddress multicastAddress, NetworkInterface networkInterface, InetAddress sourceToBlock) { if (DetectionUtil.javaVersion() < 7) { throw new UnsupportedOperationException(); } else { if (multicastAddress == null) { throw new NullPointerException("multicastAddress"); } if (sourceToBlock == null) { throw new NullPointerException("sourceToBlock"); } if (networkInterface == null) { throw new NullPointerException("networkInterface"); } synchronized (this) { if (memberships != null) { List keys = memberships.get(multicastAddress); for (MembershipKey key: keys) { if (networkInterface.equals(key.networkInterface())) { try { key.block(sourceToBlock); } catch (IOException e) { return failedFuture(this, e); } } } } } return succeededFuture(this); } } /** * Block the given sourceToBlock address for the given multicastAddress * */ public ChannelFuture block(InetAddress multicastAddress, InetAddress sourceToBlock) { try { block(multicastAddress, NetworkInterface.getByInetAddress(getLocalAddress().getAddress()), sourceToBlock); } catch (SocketException e) { return failedFuture(this, e); } return succeededFuture(this); } @Override InetSocketAddress getLocalSocketAddress() throws Exception { return (InetSocketAddress) channel.socket().getLocalSocketAddress(); } @Override InetSocketAddress getRemoteSocketAddress() throws Exception { return (InetSocketAddress) channel.socket().getRemoteSocketAddress(); } @Override public ChannelFuture write(Object message, SocketAddress remoteAddress) { if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) { return super.write(message, null); } else { return super.write(message, remoteAddress); } } } NioDatagramChannelConfig.java000066400000000000000000000032611225554127700336570ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannelConfig; /** * A {@link DatagramChannelConfig} for a NIO TCP/IP {@link DatagramChannel}. * *

Available options

* * In addition to the options provided by {@link ChannelConfig} and * {@link DatagramChannelConfig}, {@link NioDatagramChannelConfig} allows the * following options in the option map: * * * * * * * * * * * *
NameAssociated setter method
{@code "writeBufferHighWaterMark"}{@link #setWriteBufferHighWaterMark(int)}
{@code "writeBufferLowWaterMark"}{@link #setWriteBufferLowWaterMark(int)}
{@code "writeSpinCount"}{@link #setWriteSpinCount(int)}
*/ public interface NioDatagramChannelConfig extends DatagramChannelConfig, NioChannelConfig { // Tag interface } NioDatagramChannelFactory.java000066400000000000000000000222561225554127700340660ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.nio.channels.Selector; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannelFactory; import org.jboss.netty.channel.socket.InternetProtocolFamily; import org.jboss.netty.channel.socket.Worker; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; import org.jboss.netty.util.ExternalResourceReleasable; /** * A {@link DatagramChannelFactory} that creates a NIO-based connectionless * {@link DatagramChannel}. It utilizes the non-blocking I/O mode which * was introduced with NIO to serve many number of concurrent connections * efficiently. * *

How threads work

*

* There is only one thread type in a {@link NioDatagramChannelFactory}; * worker threads. * *

Worker threads

*

* One {@link NioDatagramChannelFactory} can have one or more worker * threads. A worker thread performs non-blocking read and write for one or * more {@link DatagramChannel}s in a non-blocking mode. * *

Life cycle of threads and graceful shutdown

*

* All worker threads are acquired from the {@link Executor} which was specified * when a {@link NioDatagramChannelFactory} was created. Therefore, you should * make sure the specified {@link Executor} is able to lend the sufficient * number of threads. It is the best bet to specify * {@linkplain Executors#newCachedThreadPool() a cached thread pool}. *

* All worker threads are acquired lazily, and then released when there's * nothing left to process. All the related resources such as {@link Selector} * are also released when the worker threads are released. Therefore, to shut * down a service gracefully, you should do the following: * *

    *
  1. close all channels created by the factory usually using * {@link ChannelGroup#close()}, and
  2. *
  3. call {@link #releaseExternalResources()}.
  4. *
* * Please make sure not to shut down the executor until all channels are * closed. Otherwise, you will end up with a {@link RejectedExecutionException} * and the related resources might not be released properly. * *

Limitation

*

* Multicast is not supported. Please use {@link OioDatagramChannelFactory} * instead. * * @apiviz.landmark */ public class NioDatagramChannelFactory implements DatagramChannelFactory { private final NioDatagramPipelineSink sink; private final WorkerPool workerPool; private final InternetProtocolFamily family; private boolean releasePool; /** * Create a new {@link NioDatagramChannelFactory} with a {@link Executors#newCachedThreadPool()} * and without preferred {@link InternetProtocolFamily}. Please note that the {@link InternetProtocolFamily} * of the channel will be platform (and possibly configuration) dependent and therefore * unspecified. Use {@link #NioDatagramChannelFactory(InternetProtocolFamily)} if unsure. * * See {@link #NioDatagramChannelFactory(Executor)} */ public NioDatagramChannelFactory() { this((InternetProtocolFamily) null); } /** * Create a new {@link NioDatagramChannelFactory} with a {@link Executors#newCachedThreadPool()}. * * See {@link #NioDatagramChannelFactory(Executor)} */ public NioDatagramChannelFactory(InternetProtocolFamily family) { workerPool = new NioDatagramWorkerPool(Executors.newCachedThreadPool(), SelectorUtil.DEFAULT_IO_THREADS); this.family = family; sink = new NioDatagramPipelineSink(workerPool); releasePool = true; } /** * Creates a new instance. Calling this constructor is same with calling * {@link #NioDatagramChannelFactory(Executor, int)} with 2 * the number of * available processors in the machine. The number of available processors * is obtained by {@link Runtime#availableProcessors()}. *

* Please note that the {@link InternetProtocolFamily} of the channel will be platform (and possibly * configuration) dependent and therefore unspecified. * Use {@link #NioDatagramChannelFactory(Executor, InternetProtocolFamily)} if unsure. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads */ public NioDatagramChannelFactory(final Executor workerExecutor) { this(workerExecutor, SelectorUtil.DEFAULT_IO_THREADS); } /** * Creates a new instance. *

* Please note that the {@link InternetProtocolFamily} of the channel will be platform (and possibly * configuration) dependent and therefore unspecified. * Use {@link #NioDatagramChannelFactory(Executor, int, InternetProtocolFamily)} if unsure. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param workerCount * the maximum number of I/O worker threads */ public NioDatagramChannelFactory(final Executor workerExecutor, final int workerCount) { this(new NioDatagramWorkerPool(workerExecutor, workerCount)); } /** * Creates a new instance. *

* Please note that the {@link InternetProtocolFamily} of the channel will be platform (and possibly * configuration) dependent and therefore unspecified. * Use {@link #NioDatagramChannelFactory(WorkerPool, InternetProtocolFamily)} if unsure. * * @param workerPool * the {@link WorkerPool} which will be used to obtain the {@link NioDatagramWorker} that execute * the I/O worker threads */ public NioDatagramChannelFactory(WorkerPool workerPool) { this(workerPool, null); } /** * Creates a new instance. Calling this constructor is same with calling * {@link #NioDatagramChannelFactory(Executor, int)} with 2 * the number of * available processors in the machine. The number of available processors * is obtained by {@link Runtime#availableProcessors()}. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param family * the {@link InternetProtocolFamily} to use. This should be used for UDP multicast. * Be aware that this option is only considered when running on java7+ */ public NioDatagramChannelFactory(final Executor workerExecutor, InternetProtocolFamily family) { this(workerExecutor, SelectorUtil.DEFAULT_IO_THREADS, family); } /** * Creates a new instance. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param workerCount * the maximum number of I/O worker threads * @param family * the {@link InternetProtocolFamily} to use. This should be used for UDP multicast. * Be aware that this option is only considered when running on java7+ */ public NioDatagramChannelFactory(final Executor workerExecutor, final int workerCount, InternetProtocolFamily family) { this(new NioDatagramWorkerPool(workerExecutor, workerCount), family); } /** * Creates a new instance. * * @param workerPool * the {@link WorkerPool} which will be used to obtain the {@link Worker} that execute * the I/O worker threads * @param family * the {@link InternetProtocolFamily} to use. This should be used for UDP multicast. * Be aware that this option is only considered when running on java7+ */ public NioDatagramChannelFactory(WorkerPool workerPool, InternetProtocolFamily family) { this.workerPool = workerPool; this.family = family; sink = new NioDatagramPipelineSink(workerPool); } public DatagramChannel newChannel(final ChannelPipeline pipeline) { return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker(), family); } public void shutdown() { workerPool.shutdown(); if (releasePool) { releasePool(); } } public void releaseExternalResources() { shutdown(); releasePool(); } private void releasePool() { if (workerPool instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) workerPool).releaseExternalResources(); } } } NioDatagramPipelineSink.java000066400000000000000000000150431225554127700335540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import static org.jboss.netty.channel.Channels.*; import java.net.InetSocketAddress; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; /** * Receives downstream events from a {@link ChannelPipeline}. It contains * an array of I/O workers. */ class NioDatagramPipelineSink extends AbstractNioChannelSink { private final WorkerPool workerPool; /** * Creates a new {@link NioDatagramPipelineSink} with a the number of {@link NioDatagramWorker}s * specified in workerCount. The {@link NioDatagramWorker}s take care of reading and writing * for the {@link NioDatagramChannel}. * * @param workerExecutor * the {@link Executor} that will run the {@link NioDatagramWorker}s * for this sink * @param workerCount * the number of {@link NioDatagramWorker}s for this sink */ NioDatagramPipelineSink(final WorkerPool workerPool) { this.workerPool = workerPool; } /** * Handle downstream event. * * @param pipeline the {@link ChannelPipeline} that passes down the * downstream event. * @param e The downstream event. */ public void eventSunk(final ChannelPipeline pipeline, final ChannelEvent e) throws Exception { final NioDatagramChannel channel = (NioDatagramChannel) e.getChannel(); final ChannelFuture future = e.getFuture(); if (e instanceof ChannelStateEvent) { final ChannelStateEvent stateEvent = (ChannelStateEvent) e; final ChannelState state = stateEvent.getState(); final Object value = stateEvent.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { channel.worker.close(channel, future); } break; case BOUND: if (value != null) { bind(channel, future, (InetSocketAddress) value); } else { channel.worker.close(channel, future); } break; case CONNECTED: if (value != null) { connect(channel, future, (InetSocketAddress) value); } else { NioDatagramWorker.disconnect(channel, future); } break; case INTEREST_OPS: channel.worker.setInterestOps(channel, future, ((Integer) value).intValue()); break; } } else if (e instanceof MessageEvent) { final MessageEvent event = (MessageEvent) e; final boolean offered = channel.writeBufferQueue.offer(event); assert offered; channel.worker.writeFromUserCode(channel); } } private static void close(NioDatagramChannel channel, ChannelFuture future) { try { channel.getDatagramChannel().socket().close(); if (channel.setClosed()) { future.setSuccess(); if (channel.isBound()) { fireChannelUnbound(channel); } fireChannelClosed(channel); } else { future.setSuccess(); } } catch (final Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } /** * Will bind the DatagramSocket to the passed-in address. * Every call bind will spawn a new thread using the that basically in turn */ private static void bind(final NioDatagramChannel channel, final ChannelFuture future, final InetSocketAddress address) { boolean bound = false; boolean started = false; try { // First bind the DatagramSocket the specified port. channel.getDatagramChannel().socket().bind(address); bound = true; future.setSuccess(); fireChannelBound(channel, address); channel.worker.register(channel, null); started = true; } catch (final Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (!started && bound) { close(channel, future); } } } private static void connect( NioDatagramChannel channel, ChannelFuture future, InetSocketAddress remoteAddress) { boolean bound = channel.isBound(); boolean connected = false; boolean workerStarted = false; future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); // Clear the cached address so that the next getRemoteAddress() call // updates the cache. channel.remoteAddress = null; try { channel.getDatagramChannel().connect(remoteAddress); connected = true; // Fire events. future.setSuccess(); if (!bound) { fireChannelBound(channel, channel.getLocalAddress()); } fireChannelConnected(channel, channel.getRemoteAddress()); if (!bound) { channel.worker.register(channel, future); } workerStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (connected && !workerStarted) { channel.worker.close(channel, future); } } } NioDatagramWorker nextWorker() { return workerPool.nextWorker(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramWorker.java000066400000000000000000000306621225554127700325160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousCloseException; import java.nio.channels.ClosedChannelException; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.Queue; import java.util.concurrent.Executor; import static org.jboss.netty.channel.Channels.*; /** * A class responsible for registering channels with {@link Selector}. * It also implements the {@link Selector} loop. */ public class NioDatagramWorker extends AbstractNioWorker { private final SocketReceiveBufferAllocator bufferAllocator = new SocketReceiveBufferAllocator(); /** * Sole constructor. * * @param executor the {@link Executor} used to execute {@link Runnable}s * such as {@link ChannelRegistionTask} */ NioDatagramWorker(final Executor executor) { super(executor); } @Override protected boolean read(final SelectionKey key) { final NioDatagramChannel channel = (NioDatagramChannel) key.attachment(); ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor(); final ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory(); final DatagramChannel nioChannel = (DatagramChannel) key.channel(); final int predictedRecvBufSize = predictor.nextReceiveBufferSize(); final ByteBuffer byteBuffer = bufferAllocator.get(predictedRecvBufSize).order(bufferFactory.getDefaultOrder()); boolean failure = true; SocketAddress remoteAddress = null; try { // Receive from the channel in a non blocking mode. We have already been notified that // the channel is ready to receive. remoteAddress = nioChannel.receive(byteBuffer); failure = false; } catch (ClosedChannelException e) { // Can happen, and does not need a user attention. } catch (Throwable t) { fireExceptionCaught(channel, t); } if (remoteAddress != null) { // Flip the buffer so that we can wrap it. byteBuffer.flip(); int readBytes = byteBuffer.remaining(); if (readBytes > 0) { // Update the predictor. predictor.previousReceiveBufferSize(readBytes); final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes); buffer.setBytes(0, byteBuffer); buffer.writerIndex(readBytes); // Update the predictor. predictor.previousReceiveBufferSize(readBytes); // Notify the interested parties about the newly arrived message. fireMessageReceived( channel, buffer, remoteAddress); } } if (failure) { key.cancel(); // Some JDK implementations run into an infinite loop without this. close(channel, succeededFuture(channel)); return false; } return true; } @Override protected boolean scheduleWriteIfNecessary(final AbstractNioChannel channel) { final Thread workerThread = thread; if (workerThread == null || Thread.currentThread() != workerThread) { if (channel.writeTaskInTaskQueue.compareAndSet(false, true)) { // "add" the channels writeTask to the writeTaskQueue. registerTask(channel.writeTask); } return true; } return false; } static void disconnect(NioDatagramChannel channel, ChannelFuture future) { boolean connected = channel.isConnected(); boolean iothread = isIoThread(channel); try { channel.getDatagramChannel().disconnect(); future.setSuccess(); if (connected) { if (iothread) { fireChannelDisconnected(channel); } else { fireChannelDisconnectedLater(channel); } } } catch (Throwable t) { future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } @Override protected Runnable createRegisterTask(Channel channel, ChannelFuture future) { return new ChannelRegistionTask((NioDatagramChannel) channel, future); } /** * RegisterTask is a task responsible for registering a channel with a * selector. */ private final class ChannelRegistionTask implements Runnable { private final NioDatagramChannel channel; private final ChannelFuture future; ChannelRegistionTask(final NioDatagramChannel channel, final ChannelFuture future) { this.channel = channel; this.future = future; } /** * This runnable's task. Does the actual registering by calling the * underlying DatagramChannels peer DatagramSocket register method. */ public void run() { final SocketAddress localAddress = channel.getLocalAddress(); if (localAddress == null) { if (future != null) { future.setFailure(new ClosedChannelException()); } close(channel, succeededFuture(channel)); return; } try { channel.getDatagramChannel().register( selector, channel.getRawInterestOps(), channel); if (future != null) { future.setSuccess(); } } catch (final IOException e) { if (future != null) { future.setFailure(e); } close(channel, succeededFuture(channel)); if (!(e instanceof ClosedChannelException)) { throw new ChannelException( "Failed to register a socket to the selector.", e); } } } } @Override public void writeFromUserCode(final AbstractNioChannel channel) { /* * Note that we are not checking if the channel is connected. Connected * has a different meaning in UDP and means that the channels socket is * configured to only send and receive from a given remote peer. */ if (!channel.isBound()) { cleanUpWriteBuffer(channel); return; } if (scheduleWriteIfNecessary(channel)) { return; } // From here, we are sure Thread.currentThread() == workerThread. if (channel.writeSuspended) { return; } if (channel.inWriteNowLoop) { return; } write0(channel); } @Override protected void write0(final AbstractNioChannel channel) { boolean addOpWrite = false; boolean removeOpWrite = false; long writtenBytes = 0; final SocketSendBufferPool sendBufferPool = this.sendBufferPool; final DatagramChannel ch = ((NioDatagramChannel) channel).getDatagramChannel(); final Queue writeBuffer = channel.writeBufferQueue; final int writeSpinCount = channel.getConfig().getWriteSpinCount(); synchronized (channel.writeLock) { // inform the channel that write is in-progress channel.inWriteNowLoop = true; // loop forever... for (;;) { MessageEvent evt = channel.currentWriteEvent; SocketSendBufferPool.SendBuffer buf; if (evt == null) { if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) { removeOpWrite = true; channel.writeSuspended = false; break; } channel.currentWriteBuffer = buf = sendBufferPool.acquire(evt.getMessage()); } else { buf = channel.currentWriteBuffer; } try { long localWrittenBytes = 0; SocketAddress raddr = evt.getRemoteAddress(); if (raddr == null) { for (int i = writeSpinCount; i > 0; i --) { localWrittenBytes = buf.transferTo(ch); if (localWrittenBytes != 0) { writtenBytes += localWrittenBytes; break; } if (buf.finished()) { break; } } } else { for (int i = writeSpinCount; i > 0; i --) { localWrittenBytes = buf.transferTo(ch, raddr); if (localWrittenBytes != 0) { writtenBytes += localWrittenBytes; break; } if (buf.finished()) { break; } } } if (localWrittenBytes > 0 || buf.finished()) { // Successful write - proceed to the next message. buf.release(); ChannelFuture future = evt.getFuture(); channel.currentWriteEvent = null; channel.currentWriteBuffer = null; evt = null; buf = null; future.setSuccess(); } else { // Not written at all - perhaps the kernel buffer is full. addOpWrite = true; channel.writeSuspended = true; break; } } catch (final AsynchronousCloseException e) { // Doesn't need a user attention - ignore. } catch (final Throwable t) { buf.release(); ChannelFuture future = evt.getFuture(); channel.currentWriteEvent = null; channel.currentWriteBuffer = null; // Mark the event object for garbage collection. //noinspection UnusedAssignment buf = null; //noinspection UnusedAssignment evt = null; future.setFailure(t); fireExceptionCaught(channel, t); } } channel.inWriteNowLoop = false; // Initially, the following block was executed after releasing // the writeLock, but there was a race condition, and it has to be // executed before releasing the writeLock: // // https://issues.jboss.org/browse/NETTY-410 // if (addOpWrite) { setOpWrite(channel); } else if (removeOpWrite) { clearOpWrite(channel); } } fireWriteComplete(channel, writtenBytes); } @Override public void run() { super.run(); bufferAllocator.releaseExternalResources(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioDatagramWorkerPool.java000066400000000000000000000022061225554127700333410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.util.concurrent.Executor; /** * Default implementation which hands of {@link NioDatagramWorker}'s * * */ public class NioDatagramWorkerPool extends AbstractNioWorkerPool { public NioDatagramWorkerPool(Executor executor, int workerCount) { super(executor, workerCount); } @Override @Deprecated protected NioDatagramWorker createWorker(Executor executor) { return new NioDatagramWorker(executor); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioSelector.java000066400000000000000000000021241225554127700313540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import java.nio.channels.Selector; public interface NioSelector extends Runnable { void register(Channel channel, ChannelFuture future); /** * Replaces the current {@link Selector} with a new {@link Selector} to work around the infamous epoll 100% CPU * bug. */ void rebuildSelector(); void shutdown(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioSelectorPool.java000066400000000000000000000020531225554127700322070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.nio.channels.Selector; public interface NioSelectorPool { /** * Replaces the current {@link Selector}s of the {@link Boss}es with new {@link Selector}s to work around the * infamous epoll 100% CPU bug. */ void rebuildSelectors(); /** * Shutdown the {@link NioSelectorPool} and all internal created resources */ void shutdown(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioServerBoss.java000066400000000000000000000164751225554127700317070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import java.io.IOException; import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; import java.util.concurrent.Executor; import static org.jboss.netty.channel.Channels.*; /** * Boss implementation which handles accepting of new connections */ public final class NioServerBoss extends AbstractNioSelector implements Boss { NioServerBoss(Executor bossExecutor) { super(bossExecutor); } NioServerBoss(Executor bossExecutor, ThreadNameDeterminer determiner) { super(bossExecutor, determiner); } void bind(final NioServerSocketChannel channel, final ChannelFuture future, final SocketAddress localAddress) { registerTask(new RegisterTask(channel, future, localAddress)); } @Override protected void close(SelectionKey k) { NioServerSocketChannel ch = (NioServerSocketChannel) k.attachment(); close(ch, succeededFuture(ch)); } void close(NioServerSocketChannel channel, ChannelFuture future) { boolean bound = channel.isBound(); try { channel.socket.close(); increaseCancelledKeys(); if (channel.setClosed()) { future.setSuccess(); if (bound) { fireChannelUnbound(channel); } fireChannelClosed(channel); } else { future.setSuccess(); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } @Override protected void process(Selector selector) { Set selectedKeys = selector.selectedKeys(); if (selectedKeys.isEmpty()) { return; } for (Iterator i = selectedKeys.iterator(); i.hasNext();) { SelectionKey k = i.next(); i.remove(); NioServerSocketChannel channel = (NioServerSocketChannel) k.attachment(); try { // accept connections in a for loop until no new connection is ready for (;;) { SocketChannel acceptedSocket = channel.socket.accept(); if (acceptedSocket == null) { break; } registerAcceptedChannel(channel, acceptedSocket, thread); } } catch (CancelledKeyException e) { // Raised by accept() when the server socket was closed. k.cancel(); channel.close(); } catch (SocketTimeoutException e) { // Thrown every second to get ClosedChannelException // raised. } catch (ClosedChannelException e) { // Closed as requested. } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn( "Failed to accept a connection.", t); } try { Thread.sleep(1000); } catch (InterruptedException e1) { // Ignore } } } } private static void registerAcceptedChannel(NioServerSocketChannel parent, SocketChannel acceptedSocket, Thread currentThread) { try { ChannelSink sink = parent.getPipeline().getSink(); ChannelPipeline pipeline = parent.getConfig().getPipelineFactory().getPipeline(); NioWorker worker = parent.workerPool.nextWorker(); worker.register(new NioAcceptedSocketChannel( parent.getFactory(), pipeline, parent, sink , acceptedSocket, worker, currentThread), null); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn( "Failed to initialize an accepted socket.", e); } try { acceptedSocket.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially accepted socket.", e2); } } } } @Override protected int select(Selector selector) throws IOException { // Just do a blocking select without any timeout // as this thread does not execute anything else. return selector.select(); } @Override protected ThreadRenamingRunnable newThreadRenamingRunnable(int id, ThreadNameDeterminer determiner) { return new ThreadRenamingRunnable(this, "New I/O server boss #" + id, determiner); } @Override protected Runnable createRegisterTask(Channel channel, ChannelFuture future) { return new RegisterTask((NioServerSocketChannel) channel, future, null); } private final class RegisterTask implements Runnable { private final NioServerSocketChannel channel; private final ChannelFuture future; private final SocketAddress localAddress; public RegisterTask(final NioServerSocketChannel channel, final ChannelFuture future, final SocketAddress localAddress) { this.channel = channel; this.future = future; this.localAddress = localAddress; } public void run() { boolean bound = false; boolean registered = false; try { channel.socket.socket().bind(localAddress, channel.getConfig().getBacklog()); bound = true; future.setSuccess(); fireChannelBound(channel, channel.getLocalAddress()); channel.socket.register(selector, SelectionKey.OP_ACCEPT, channel); registered = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (!registered && bound) { close(channel, future); } } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioServerBossPool.java000066400000000000000000000041471225554127700325320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.util.ThreadNameDeterminer; import java.util.concurrent.Executor; /** * Holds {@link NioServerBoss} instances to use */ public class NioServerBossPool extends AbstractNioBossPool { private final ThreadNameDeterminer determiner; /** * Create a new instance * * @param bossExecutor the {@link Executor} to use for server the {@link NioServerBoss} * @param bossCount the number of {@link NioServerBoss} instances this {@link NioServerBossPool} will hold * @param determiner the {@link ThreadNameDeterminer} to use for name the threads. Use {@code null} * if you not want to set one explicit. */ public NioServerBossPool(Executor bossExecutor, int bossCount, ThreadNameDeterminer determiner) { super(bossExecutor, bossCount, false); this.determiner = determiner; init(); } /** * Create a new instance using no {@link ThreadNameDeterminer} * * @param bossExecutor the {@link Executor} to use for server the {@link NioServerBoss} * @param bossCount the number of {@link NioServerBoss} instances this {@link NioServerBossPool} will hold */ public NioServerBossPool(Executor bossExecutor, int bossCount) { this(bossExecutor, bossCount, null); } @Override protected NioServerBoss newBoss(Executor executor) { return new NioServerBoss(executor, determiner); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioServerSocketChannel.java000066400000000000000000000063461225554127700335160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import static org.jboss.netty.channel.Channels.*; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; import org.jboss.netty.channel.AbstractServerChannel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.socket.DefaultServerSocketChannelConfig; import org.jboss.netty.channel.socket.ServerSocketChannelConfig; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; class NioServerSocketChannel extends AbstractServerChannel implements org.jboss.netty.channel.socket.ServerSocketChannel { private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class); final ServerSocketChannel socket; final Boss boss; final WorkerPool workerPool; private final ServerSocketChannelConfig config; NioServerSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, Boss boss, WorkerPool workerPool) { super(factory, pipeline, sink); this.boss = boss; this.workerPool = workerPool; try { socket = ServerSocketChannel.open(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } try { socket.configureBlocking(false); } catch (IOException e) { try { socket.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e2); } } throw new ChannelException("Failed to enter non-blocking mode.", e); } config = new DefaultServerSocketChannelConfig(socket.socket()); fireChannelOpen(this); } public ServerSocketChannelConfig getConfig() { return config; } public InetSocketAddress getLocalAddress() { return (InetSocketAddress) socket.socket().getLocalSocketAddress(); } public InetSocketAddress getRemoteAddress() { return null; } public boolean isBound() { return isOpen() && socket.socket().isBound(); } @Override protected boolean setClosed() { return super.setClosed(); } } NioServerSocketChannelFactory.java000066400000000000000000000233561225554127700347670ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import java.nio.channels.Selector; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.ServerSocketChannel; import org.jboss.netty.channel.socket.ServerSocketChannelFactory; import org.jboss.netty.util.ExternalResourceReleasable; /** * A {@link ServerSocketChannelFactory} which creates a server-side NIO-based * {@link ServerSocketChannel}. It utilizes the non-blocking I/O mode which * was introduced with NIO to serve many number of concurrent connections * efficiently. * *

How threads work

*

* There are two types of threads in a {@link NioServerSocketChannelFactory}; * one is boss thread and the other is worker thread. * *

Boss threads

*

* Each bound {@link ServerSocketChannel} has its own boss thread. * For example, if you opened two server ports such as 80 and 443, you will * have two boss threads. A boss thread accepts incoming connections until * the port is unbound. Once a connection is accepted successfully, the boss * thread passes the accepted {@link Channel} to one of the worker * threads that the {@link NioServerSocketChannelFactory} manages. * *

Worker threads

*

* One {@link NioServerSocketChannelFactory} can have one or more worker * threads. A worker thread performs non-blocking read and write for one or * more {@link Channel}s in a non-blocking mode. * *

Life cycle of threads and graceful shutdown

*

* All threads are acquired from the {@link Executor}s which were specified * when a {@link NioServerSocketChannelFactory} was created. Boss threads are * acquired from the {@code bossExecutor}, and worker threads are acquired from * the {@code workerExecutor}. Therefore, you should make sure the specified * {@link Executor}s are able to lend the sufficient number of threads. * It is the best bet to specify {@linkplain Executors#newCachedThreadPool() a cached thread pool}. *

* Both boss and worker threads are acquired lazily, and then released when * there's nothing left to process. All the related resources such as * {@link Selector} are also released when the boss and worker threads are * released. Therefore, to shut down a service gracefully, you should do the * following: * *

    *
  1. unbind all channels created by the factory, *
  2. close all child channels accepted by the unbound channels, and * (these two steps so far is usually done using {@link ChannelGroup#close()})
  3. *
  4. call {@link #releaseExternalResources()}.
  5. *
* * Please make sure not to shut down the executor until all channels are * closed. Otherwise, you will end up with a {@link RejectedExecutionException} * and the related resources might not be released properly. * * @apiviz.landmark */ public class NioServerSocketChannelFactory implements ServerSocketChannelFactory { private final WorkerPool workerPool; private final NioServerSocketPipelineSink sink; private final BossPool bossPool; private boolean releasePools; /** * Create a new {@link NioServerSocketChannelFactory} using {@link Executors#newCachedThreadPool()} * for the boss and worker. * * See {@link #NioServerSocketChannelFactory(Executor, Executor)} */ public NioServerSocketChannelFactory() { this(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); releasePools = true; } /** * Creates a new instance. Calling this constructor is same with calling * {@link #NioServerSocketChannelFactory(Executor, Executor, int)} with * the worker executor passed into {@link #getMaxThreads(Executor)}. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads */ public NioServerSocketChannelFactory( Executor bossExecutor, Executor workerExecutor) { this(bossExecutor, workerExecutor, getMaxThreads(workerExecutor)); } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param workerCount * the maximum number of I/O worker threads */ public NioServerSocketChannelFactory( Executor bossExecutor, Executor workerExecutor, int workerCount) { this(bossExecutor, 1, workerExecutor, workerCount); } /** * Create a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param bossCount * the number of boss threads * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param workerCount * the maximum number of I/O worker threads */ public NioServerSocketChannelFactory( Executor bossExecutor, int bossCount, Executor workerExecutor, int workerCount) { this(bossExecutor, bossCount, new NioWorkerPool(workerExecutor, workerCount)); } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param workerPool * the {@link WorkerPool} which will be used to obtain the {@link NioWorker} that execute * the I/O worker threads */ public NioServerSocketChannelFactory( Executor bossExecutor, WorkerPool workerPool) { this(bossExecutor, 1 , workerPool); } /** * Create a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param bossCount * the number of boss threads * @param workerPool * the {@link WorkerPool} which will be used to obtain the {@link NioWorker} that execute * the I/O worker threads */ public NioServerSocketChannelFactory( Executor bossExecutor, int bossCount, WorkerPool workerPool) { this(new NioServerBossPool(bossExecutor, bossCount, null), workerPool); } /** * Create a new instance. * * @param bossPool * the {@link BossPool} which will be used to obtain the {@link NioServerBoss} that execute * the I/O for accept new connections * @param workerPool * the {@link WorkerPool} which will be used to obtain the {@link NioWorker} that execute * the I/O worker threads */ public NioServerSocketChannelFactory(BossPool bossPool, WorkerPool workerPool) { if (bossPool == null) { throw new NullPointerException("bossExecutor"); } if (workerPool == null) { throw new NullPointerException("workerPool"); } this.bossPool = bossPool; this.workerPool = workerPool; sink = new NioServerSocketPipelineSink(); } public ServerSocketChannel newChannel(ChannelPipeline pipeline) { return new NioServerSocketChannel(this, pipeline, sink, bossPool.nextBoss(), workerPool); } public void shutdown() { bossPool.shutdown(); workerPool.shutdown(); if (releasePools) { releasePools(); } } public void releaseExternalResources() { shutdown(); releasePools(); } private void releasePools() { if (bossPool instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) bossPool).releaseExternalResources(); } if (workerPool instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) workerPool).releaseExternalResources(); } } /** * Returns number of max threads for the {@link NioWorkerPool} to use. If * the * {@link Executor} is a {@link ThreadPoolExecutor}, check its * maximum * pool size and return either it's maximum or * {@link SelectorUtil#DEFAULT_IO_THREADS}, whichever is lower. Note that * {@link SelectorUtil#DEFAULT_IO_THREADS} is 2 * the number of available * processors in the machine. The number of available processors is * obtained by {@link Runtime#availableProcessors()}. * * @param executor * the {@link Executor} which will execute the I/O worker threads * @return * number of maximum threads the NioWorkerPool should use */ private static int getMaxThreads(Executor executor) { if (executor instanceof ThreadPoolExecutor) { final int maxThreads = ((ThreadPoolExecutor) executor).getMaximumPoolSize(); return Math.min(maxThreads, SelectorUtil.DEFAULT_IO_THREADS); } return SelectorUtil.DEFAULT_IO_THREADS; } } NioServerSocketPipelineSink.java000066400000000000000000000071641225554127700344600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import java.net.SocketAddress; class NioServerSocketPipelineSink extends AbstractNioChannelSink { public void eventSunk( ChannelPipeline pipeline, ChannelEvent e) throws Exception { Channel channel = e.getChannel(); if (channel instanceof NioServerSocketChannel) { handleServerSocket(e); } else if (channel instanceof NioSocketChannel) { handleAcceptedSocket(e); } } private static void handleServerSocket(ChannelEvent e) { if (!(e instanceof ChannelStateEvent)) { return; } ChannelStateEvent event = (ChannelStateEvent) e; NioServerSocketChannel channel = (NioServerSocketChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { ((NioServerBoss) channel.boss).close(channel, future); } break; case BOUND: if (value != null) { ((NioServerBoss) channel.boss).bind(channel, future, (SocketAddress) value); } else { ((NioServerBoss) channel.boss).close(channel, future); } break; default: break; } } private static void handleAcceptedSocket(ChannelEvent e) { if (e instanceof ChannelStateEvent) { ChannelStateEvent event = (ChannelStateEvent) e; NioSocketChannel channel = (NioSocketChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { channel.worker.close(channel, future); } break; case BOUND: case CONNECTED: if (value == null) { channel.worker.close(channel, future); } break; case INTEREST_OPS: channel.worker.setInterestOps(channel, future, ((Integer) value).intValue()); break; } } else if (e instanceof MessageEvent) { MessageEvent event = (MessageEvent) e; NioSocketChannel channel = (NioSocketChannel) event.getChannel(); boolean offered = channel.writeBufferQueue.offer(event); assert offered; channel.worker.writeFromUserCode(channel); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioSocketChannel.java000066400000000000000000000063511225554127700323230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.SocketChannel; public class NioSocketChannel extends AbstractNioChannel implements org.jboss.netty.channel.socket.SocketChannel { private static final int ST_OPEN = 0; private static final int ST_BOUND = 1; private static final int ST_CONNECTED = 2; private static final int ST_CLOSED = -1; @SuppressWarnings("RedundantFieldInitialization") volatile int state = ST_OPEN; private final NioSocketChannelConfig config; public NioSocketChannel( Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, SocketChannel socket, NioWorker worker) { super(parent, factory, pipeline, sink, worker, socket); config = new DefaultNioSocketChannelConfig(socket.socket()); } @Override public NioWorker getWorker() { return (NioWorker) super.getWorker(); } @Override public NioSocketChannelConfig getConfig() { return config; } @Override public boolean isOpen() { return state >= ST_OPEN; } public boolean isBound() { return state >= ST_BOUND; } public boolean isConnected() { return state == ST_CONNECTED; } final void setBound() { assert state == ST_OPEN : "Invalid state: " + state; state = ST_BOUND; } final void setConnected() { if (state != ST_CLOSED) { state = ST_CONNECTED; } } @Override protected boolean setClosed() { if (super.setClosed()) { state = ST_CLOSED; return true; } return false; } @Override InetSocketAddress getLocalSocketAddress() throws Exception { return (InetSocketAddress) channel.socket().getLocalSocketAddress(); } @Override InetSocketAddress getRemoteSocketAddress() throws Exception { return (InetSocketAddress) channel.socket().getRemoteSocketAddress(); } @Override public ChannelFuture write(Object message, SocketAddress remoteAddress) { if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) { return super.write(message, null); } else { return getUnsupportedOperationFuture(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioSocketChannelConfig.java000066400000000000000000000077251225554127700334570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictor; import org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import org.jboss.netty.channel.ReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.channel.socket.SocketChannelConfig; /** * A {@link SocketChannelConfig} for a NIO TCP/IP {@link SocketChannel}. * *

Available options

* * In addition to the options provided by {@link ChannelConfig} and * {@link SocketChannelConfig}, {@link NioSocketChannelConfig} allows the * following options in the option map: * * * * * * * * * * * * * * * * * *
NameAssociated setter method
{@code "writeBufferHighWaterMark"}{@link #setWriteBufferHighWaterMark(int)}
{@code "writeBufferLowWaterMark"}{@link #setWriteBufferLowWaterMark(int)}
{@code "writeSpinCount"}{@link #setWriteSpinCount(int)}
{@code "receiveBufferSizePredictor"}{@link #setReceiveBufferSizePredictor(ReceiveBufferSizePredictor)}
{@code "receiveBufferSizePredictorFactory"}{@link #setReceiveBufferSizePredictorFactory(ReceiveBufferSizePredictorFactory)}
*/ public interface NioSocketChannelConfig extends SocketChannelConfig, NioChannelConfig { /** * Returns the {@link ReceiveBufferSizePredictor} which predicts the * number of readable bytes in the socket receive buffer. The default * predictor is {@link AdaptiveReceiveBufferSizePredictor}(64, 1024, 65536). */ ReceiveBufferSizePredictor getReceiveBufferSizePredictor(); /** * Sets the {@link ReceiveBufferSizePredictor} which predicts the * number of readable bytes in the socket receive buffer. The default * predictor is {@link AdaptiveReceiveBufferSizePredictor}(64, 1024, 65536). */ void setReceiveBufferSizePredictor(ReceiveBufferSizePredictor predictor); /** * Returns the {@link ReceiveBufferSizePredictorFactory} which creates a new * {@link ReceiveBufferSizePredictor} when a new channel is created and * no {@link ReceiveBufferSizePredictor} was set. If no predictor was set * for the channel, {@link #setReceiveBufferSizePredictor(ReceiveBufferSizePredictor)} * will be called with the new predictor. The default factory is * {@link AdaptiveReceiveBufferSizePredictorFactory}(64, 1024, 65536). */ ReceiveBufferSizePredictorFactory getReceiveBufferSizePredictorFactory(); /** * Sets the {@link ReceiveBufferSizePredictor} which creates a new * {@link ReceiveBufferSizePredictor} when a new channel is created and * no {@link ReceiveBufferSizePredictor} was set. If no predictor was set * for the channel, {@link #setReceiveBufferSizePredictor(ReceiveBufferSizePredictor)} * will be called with the new predictor. The default factory is * {@link AdaptiveReceiveBufferSizePredictorFactory}(64, 1024, 65536). */ void setReceiveBufferSizePredictorFactory(ReceiveBufferSizePredictorFactory predictorFactory); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioWorker.java000066400000000000000000000137741225554127700310620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import org.jboss.netty.util.ThreadNameDeterminer; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.concurrent.Executor; import static org.jboss.netty.channel.Channels.*; public class NioWorker extends AbstractNioWorker { private final SocketReceiveBufferAllocator recvBufferPool = new SocketReceiveBufferAllocator(); public NioWorker(Executor executor) { super(executor); } public NioWorker(Executor executor, ThreadNameDeterminer determiner) { super(executor, determiner); } @Override protected boolean read(SelectionKey k) { final SocketChannel ch = (SocketChannel) k.channel(); final NioSocketChannel channel = (NioSocketChannel) k.attachment(); final ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor(); final int predictedRecvBufSize = predictor.nextReceiveBufferSize(); final ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory(); int ret = 0; int readBytes = 0; boolean failure = true; ByteBuffer bb = recvBufferPool.get(predictedRecvBufSize).order(bufferFactory.getDefaultOrder()); try { while ((ret = ch.read(bb)) > 0) { readBytes += ret; if (!bb.hasRemaining()) { break; } } failure = false; } catch (ClosedChannelException e) { // Can happen, and does not need a user attention. } catch (Throwable t) { fireExceptionCaught(channel, t); } if (readBytes > 0) { bb.flip(); final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes); buffer.setBytes(0, bb); buffer.writerIndex(readBytes); // Update the predictor. predictor.previousReceiveBufferSize(readBytes); // Fire the event. fireMessageReceived(channel, buffer); } if (ret < 0 || failure) { k.cancel(); // Some JDK implementations run into an infinite loop without this. close(channel, succeededFuture(channel)); return false; } return true; } @Override protected boolean scheduleWriteIfNecessary(final AbstractNioChannel channel) { final Thread currentThread = Thread.currentThread(); final Thread workerThread = thread; if (currentThread != workerThread) { if (channel.writeTaskInTaskQueue.compareAndSet(false, true)) { registerTask(channel.writeTask); } return true; } return false; } @Override protected Runnable createRegisterTask(Channel channel, ChannelFuture future) { boolean server = !(channel instanceof NioClientSocketChannel); return new RegisterTask((NioSocketChannel) channel, future, server); } private final class RegisterTask implements Runnable { private final NioSocketChannel channel; private final ChannelFuture future; private final boolean server; RegisterTask( NioSocketChannel channel, ChannelFuture future, boolean server) { this.channel = channel; this.future = future; this.server = server; } public void run() { SocketAddress localAddress = channel.getLocalAddress(); SocketAddress remoteAddress = channel.getRemoteAddress(); if (localAddress == null || remoteAddress == null) { if (future != null) { future.setFailure(new ClosedChannelException()); } close(channel, succeededFuture(channel)); return; } try { if (server) { channel.channel.configureBlocking(false); } channel.channel.register( selector, channel.getRawInterestOps(), channel); if (future != null) { channel.setConnected(); future.setSuccess(); } if (server || !((NioClientSocketChannel) channel).boundManually) { fireChannelBound(channel, localAddress); } fireChannelConnected(channel, remoteAddress); } catch (IOException e) { if (future != null) { future.setFailure(e); } close(channel, succeededFuture(channel)); if (!(e instanceof ClosedChannelException)) { throw new ChannelException( "Failed to register a socket to the selector.", e); } } } } @Override public void run() { super.run(); recvBufferPool.releaseExternalResources(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/NioWorkerPool.java000066400000000000000000000026601225554127700317040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.util.ThreadNameDeterminer; import java.util.concurrent.Executor; /** * Default implementation which hands of {@link NioWorker}'s * * */ public class NioWorkerPool extends AbstractNioWorkerPool { private final ThreadNameDeterminer determiner; public NioWorkerPool(Executor workerExecutor, int workerCount) { this(workerExecutor, workerCount, null); } public NioWorkerPool(Executor workerExecutor, int workerCount, ThreadNameDeterminer determiner) { super(workerExecutor, workerCount, false); this.determiner = determiner; init(); } @Override @Deprecated protected NioWorker createWorker(Executor executor) { return new NioWorker(executor, determiner); } } ProtocolFamilyConverter.java000066400000000000000000000026421225554127700337070ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.socket.InternetProtocolFamily; import java.net.ProtocolFamily; import java.net.StandardProtocolFamily; /** * Helper class which convert the {@link InternetProtocolFamily}. * * */ final class ProtocolFamilyConverter { private ProtocolFamilyConverter() { // Utility class } /** * Convert the {@link InternetProtocolFamily}. This MUST only be called on jdk version >= 7. */ public static ProtocolFamily convert(InternetProtocolFamily family) { switch (family) { case IPv4: return StandardProtocolFamily.INET; case IPv6: return StandardProtocolFamily.INET6; default: throw new IllegalArgumentException(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/SelectorUtil.java000066400000000000000000000057371225554127700315610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.SystemPropertyUtil; import java.io.IOException; import java.nio.channels.CancelledKeyException; import java.nio.channels.Selector; import java.util.concurrent.TimeUnit; final class SelectorUtil { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelectorUtil.class); static final int DEFAULT_IO_THREADS = Runtime.getRuntime().availableProcessors() * 2; static final long DEFAULT_SELECT_TIMEOUT = 500; static final long SELECT_TIMEOUT = SystemPropertyUtil.getLong("org.jboss.netty.selectTimeout", DEFAULT_SELECT_TIMEOUT); static final long SELECT_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(SELECT_TIMEOUT); static final boolean EPOLL_BUG_WORKAROUND = SystemPropertyUtil.getBoolean("org.jboss.netty.epollBugWorkaround", false); // Workaround for JDK NIO bug. // // See: // - http://bugs.sun.com/view_bug.do?bug_id=6427854 // - https://github.com/netty/netty/issues/203 static { String key = "sun.nio.ch.bugLevel"; try { String buglevel = System.getProperty(key); if (buglevel == null) { System.setProperty(key, ""); } } catch (SecurityException e) { if (logger.isDebugEnabled()) { logger.debug("Unable to get/set System Property '" + key + '\'', e); } } if (logger.isDebugEnabled()) { logger.debug("Using select timeout of " + SELECT_TIMEOUT); logger.debug("Epoll-bug workaround enabled = " + EPOLL_BUG_WORKAROUND); } } static Selector open() throws IOException { return Selector.open(); } static int select(Selector selector) throws IOException { try { return selector.select(SELECT_TIMEOUT); } catch (CancelledKeyException e) { if (logger.isDebugEnabled()) { logger.debug( CancelledKeyException.class.getSimpleName() + " raised by a Selector - JDK bug?", e); } // Harmless exception - log anyway } return -1; } private SelectorUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/ShareableWorkerPool.java000066400000000000000000000034271225554127700330470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.socket.Worker; import org.jboss.netty.util.ExternalResourceReleasable; /** * This implementation of a {@link WorkerPool} should be used if you plan to share a * {@link WorkerPool} between different Factories. You will need to call {@link #destroy()} by your * own once you want to release any resources of it. * * */ public final class ShareableWorkerPool implements WorkerPool { private final WorkerPool wrapped; public ShareableWorkerPool(WorkerPool wrapped) { this.wrapped = wrapped; } public E nextWorker() { return wrapped.nextWorker(); } public void rebuildSelectors() { wrapped.rebuildSelectors(); } /** * Destroy the {@link ShareableWorkerPool} and release all resources. After this is called its not usable anymore */ public void destroy() { wrapped.shutdown(); if (wrapped instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) wrapped).releaseExternalResources(); } } public void shutdown() { // do nothing } } SocketReceiveBufferAllocator.java000066400000000000000000000045211225554127700346000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.internal.ByteBufferUtil; import java.nio.ByteBuffer; final class SocketReceiveBufferAllocator implements ExternalResourceReleasable { private ByteBuffer buf; private int exceedCount; private final int maxExceedCount; private final int percentual; SocketReceiveBufferAllocator() { this(16, 80); } SocketReceiveBufferAllocator(int maxExceedCount, int percentual) { this.maxExceedCount = maxExceedCount; this.percentual = percentual; } ByteBuffer get(int size) { if (buf == null) { return newBuffer(size); } if (buf.capacity() < size) { return newBuffer(size); } if (buf.capacity() * percentual / 100 > size) { if (++exceedCount == maxExceedCount) { return newBuffer(size); } else { buf.clear(); } } else { exceedCount = 0; buf.clear(); } return buf; } private ByteBuffer newBuffer(int size) { if (buf != null) { exceedCount = 0; ByteBufferUtil.destroy(buf); } buf = ByteBuffer.allocateDirect(normalizeCapacity(size)); return buf; } private static int normalizeCapacity(int capacity) { // Normalize to multiple of 1024 int q = capacity >>> 10; int r = capacity & 1023; if (r != 0) { q ++; } return q << 10; } public void releaseExternalResources() { if (buf != null) { ByteBufferUtil.destroy(buf); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/SocketSendBufferPool.java000066400000000000000000000257361225554127700331720ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.CompositeChannelBuffer; import org.jboss.netty.channel.DefaultFileRegion; import org.jboss.netty.channel.FileRegion; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.internal.ByteBufferUtil; import java.io.IOException; import java.lang.ref.SoftReference; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.GatheringByteChannel; import java.nio.channels.WritableByteChannel; final class SocketSendBufferPool implements ExternalResourceReleasable { private static final SendBuffer EMPTY_BUFFER = new EmptySendBuffer(); private static final int DEFAULT_PREALLOCATION_SIZE = 65536; private static final int ALIGN_SHIFT = 4; private static final int ALIGN_MASK = 15; private PreallocationRef poolHead; private Preallocation current = new Preallocation(DEFAULT_PREALLOCATION_SIZE); SendBuffer acquire(Object message) { if (message instanceof ChannelBuffer) { return acquire((ChannelBuffer) message); } if (message instanceof FileRegion) { return acquire((FileRegion) message); } throw new IllegalArgumentException( "unsupported message type: " + message.getClass()); } private SendBuffer acquire(FileRegion src) { if (src.getCount() == 0) { return EMPTY_BUFFER; } return new FileSendBuffer(src); } private SendBuffer acquire(ChannelBuffer src) { final int size = src.readableBytes(); if (size == 0) { return EMPTY_BUFFER; } if (src instanceof CompositeChannelBuffer && ((CompositeChannelBuffer) src).useGathering()) { return new GatheringSendBuffer(src.toByteBuffers()); } if (src.isDirect()) { return new UnpooledSendBuffer(src.toByteBuffer()); } if (src.readableBytes() > DEFAULT_PREALLOCATION_SIZE) { return new UnpooledSendBuffer(src.toByteBuffer()); } Preallocation current = this.current; ByteBuffer buffer = current.buffer; int remaining = buffer.remaining(); PooledSendBuffer dst; if (size < remaining) { int nextPos = buffer.position() + size; ByteBuffer slice = buffer.duplicate(); buffer.position(align(nextPos)); slice.limit(nextPos); current.refCnt ++; dst = new PooledSendBuffer(current, slice); } else if (size > remaining) { this.current = current = getPreallocation(); buffer = current.buffer; ByteBuffer slice = buffer.duplicate(); buffer.position(align(size)); slice.limit(size); current.refCnt ++; dst = new PooledSendBuffer(current, slice); } else { // size == remaining current.refCnt ++; this.current = getPreallocation0(); dst = new PooledSendBuffer(current, current.buffer); } ByteBuffer dstbuf = dst.buffer; dstbuf.mark(); src.getBytes(src.readerIndex(), dstbuf); dstbuf.reset(); return dst; } private Preallocation getPreallocation() { Preallocation current = this.current; if (current.refCnt == 0) { current.buffer.clear(); return current; } return getPreallocation0(); } private Preallocation getPreallocation0() { PreallocationRef ref = poolHead; if (ref != null) { do { Preallocation p = ref.get(); ref = ref.next; if (p != null) { poolHead = ref; return p; } } while (ref != null); poolHead = ref; } return new Preallocation(DEFAULT_PREALLOCATION_SIZE); } private static int align(int pos) { int q = pos >>> ALIGN_SHIFT; int r = pos & ALIGN_MASK; if (r != 0) { q ++; } return q << ALIGN_SHIFT; } private static final class Preallocation { final ByteBuffer buffer; int refCnt; Preallocation(int capacity) { buffer = ByteBuffer.allocateDirect(capacity); } } private final class PreallocationRef extends SoftReference { final PreallocationRef next; PreallocationRef(Preallocation prealloation, PreallocationRef next) { super(prealloation); this.next = next; } } interface SendBuffer { boolean finished(); long writtenBytes(); long totalBytes(); long transferTo(WritableByteChannel ch) throws IOException; long transferTo(DatagramChannel ch, SocketAddress raddr) throws IOException; void release(); } static class UnpooledSendBuffer implements SendBuffer { final ByteBuffer buffer; final int initialPos; UnpooledSendBuffer(ByteBuffer buffer) { this.buffer = buffer; initialPos = buffer.position(); } public final boolean finished() { return !buffer.hasRemaining(); } public final long writtenBytes() { return buffer.position() - initialPos; } public final long totalBytes() { return buffer.limit() - initialPos; } public final long transferTo(WritableByteChannel ch) throws IOException { return ch.write(buffer); } public final long transferTo(DatagramChannel ch, SocketAddress raddr) throws IOException { return ch.send(buffer, raddr); } public void release() { // Unpooled. } } final class PooledSendBuffer extends UnpooledSendBuffer { private final Preallocation parent; PooledSendBuffer(Preallocation parent, ByteBuffer buffer) { super(buffer); this.parent = parent; } @Override public void release() { final Preallocation parent = this.parent; if (-- parent.refCnt == 0) { parent.buffer.clear(); if (parent != current) { poolHead = new PreallocationRef(parent, poolHead); } } } } static class GatheringSendBuffer implements SendBuffer { private final ByteBuffer[] buffers; private final int last; private long written; private final int total; GatheringSendBuffer(ByteBuffer[] buffers) { this.buffers = buffers; last = buffers.length - 1; int total = 0; for (ByteBuffer buf: buffers) { total += buf.remaining(); } this.total = total; } public boolean finished() { return !buffers[last].hasRemaining(); } public long writtenBytes() { return written; } public long totalBytes() { return total; } public long transferTo(WritableByteChannel ch) throws IOException { if (ch instanceof GatheringByteChannel) { long w = ((GatheringByteChannel) ch).write(buffers); written += w; return w; } else { int send = 0; for (ByteBuffer buf: buffers) { if (buf.hasRemaining()) { int w = ch.write(buf); if (w == 0) { break; } else { send += w; } } } written += send; return send; } } public long transferTo(DatagramChannel ch, SocketAddress raddr) throws IOException { int send = 0; for (ByteBuffer buf: buffers) { if (buf.hasRemaining()) { int w = ch.send(buf, raddr); if (w == 0) { break; } else { send += w; } } } written += send; return send; } public void release() { // nothing todo } } final class FileSendBuffer implements SendBuffer { private final FileRegion file; private long writtenBytes; FileSendBuffer(FileRegion file) { this.file = file; } public boolean finished() { return writtenBytes >= file.getCount(); } public long writtenBytes() { return writtenBytes; } public long totalBytes() { return file.getCount(); } public long transferTo(WritableByteChannel ch) throws IOException { long localWrittenBytes = file.transferTo(ch, writtenBytes); writtenBytes += localWrittenBytes; return localWrittenBytes; } public long transferTo(DatagramChannel ch, SocketAddress raddr) { throw new UnsupportedOperationException(); } public void release() { if (file instanceof DefaultFileRegion) { if (((DefaultFileRegion) file).releaseAfterTransfer()) { // Make sure the FileRegion resource are released otherwise it may cause a FD // leak or something similar file.releaseExternalResources(); } } } } static final class EmptySendBuffer implements SendBuffer { public boolean finished() { return true; } public long writtenBytes() { return 0; } public long totalBytes() { return 0; } public long transferTo(WritableByteChannel ch) { return 0; } public long transferTo(DatagramChannel ch, SocketAddress raddr) { return 0; } public void release() { // Unpooled. } } public void releaseExternalResources() { if (current.buffer != null) { ByteBufferUtil.destroy(current.buffer); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/WorkerPool.java000066400000000000000000000017531225554127700312400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.channel.socket.Worker; /** * The {@link WorkerPool} is responsible to hand of {@link Worker}'s on demand * */ public interface WorkerPool extends NioSelectorPool { /** * Return the next {@link Worker} to use * * @return worker */ E nextWorker(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/nio/package-info.java000066400000000000000000000015231225554127700314540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * NIO-based socket channel * API implementation - recommended for a large number of connections (>= 1000). */ package org.jboss.netty.channel.socket.nio; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/000077500000000000000000000000001225554127700262655ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/AbstractOioChannel.java000066400000000000000000000066421225554127700326430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.jboss.netty.channel.AbstractChannel; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.socket.Worker; abstract class AbstractOioChannel extends AbstractChannel { private volatile InetSocketAddress localAddress; volatile InetSocketAddress remoteAddress; volatile Thread workerThread; volatile Worker worker; final Object interestOpsLock = new Object(); AbstractOioChannel( Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(parent, factory, pipeline, sink); } @Override protected boolean setClosed() { return super.setClosed(); } @Override protected void setInterestOpsNow(int interestOps) { super.setInterestOpsNow(interestOps); } @Override public ChannelFuture write(Object message, SocketAddress remoteAddress) { if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) { return super.write(message, null); } else { return super.write(message, remoteAddress); } } public boolean isBound() { return isOpen() && isSocketBound(); } public boolean isConnected() { return isOpen() && isSocketConnected(); } public InetSocketAddress getLocalAddress() { InetSocketAddress localAddress = this.localAddress; if (localAddress == null) { try { this.localAddress = localAddress = getLocalSocketAddress(); } catch (Throwable t) { // Sometimes fails on a closed socket in Windows. return null; } } return localAddress; } public InetSocketAddress getRemoteAddress() { InetSocketAddress remoteAddress = this.remoteAddress; if (remoteAddress == null) { try { this.remoteAddress = remoteAddress = getRemoteSocketAddress(); } catch (Throwable t) { // Sometimes fails on a closed socket in Windows. return null; } } return remoteAddress; } abstract boolean isSocketBound(); abstract boolean isSocketConnected(); abstract boolean isSocketClosed(); abstract InetSocketAddress getLocalSocketAddress() throws Exception; abstract InetSocketAddress getRemoteSocketAddress() throws Exception; abstract void closeSocket() throws IOException; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/AbstractOioChannelSink.java000066400000000000000000000040421225554127700334600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.channel.AbstractChannelSink; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.socket.ChannelRunnableWrapper; import org.jboss.netty.channel.socket.Worker; public abstract class AbstractOioChannelSink extends AbstractChannelSink { @Override public ChannelFuture execute(final ChannelPipeline pipeline, final Runnable task) { Channel ch = pipeline.getChannel(); if (ch instanceof AbstractOioChannel) { AbstractOioChannel channel = (AbstractOioChannel) ch; Worker worker = channel.worker; if (worker != null) { ChannelRunnableWrapper wrapper = new ChannelRunnableWrapper(pipeline.getChannel(), task); channel.worker.executeInIoThread(wrapper); return wrapper; } } return super.execute(pipeline, task); } @Override protected boolean isFireExceptionCaughtLater(ChannelEvent event, Throwable actualCause) { Channel channel = event.getChannel(); boolean fireLater = false; if (channel instanceof AbstractOioChannel) { fireLater = !AbstractOioWorker.isIoThread((AbstractOioChannel) channel); } return fireLater; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/AbstractOioWorker.java000066400000000000000000000216201225554127700325350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.Worker; import java.io.IOException; import java.net.SocketTimeoutException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import static org.jboss.netty.channel.Channels.*; /** * Abstract base class for Oio-Worker implementations * * @param {@link AbstractOioChannel} */ abstract class AbstractOioWorker implements Worker { private final Queue eventQueue = new ConcurrentLinkedQueue(); protected final C channel; /** * If this worker has been started thread will be a reference to the thread * used when starting. i.e. the current thread when the run method is executed. */ protected volatile Thread thread; private volatile boolean done; protected AbstractOioWorker(C channel) { this.channel = channel; channel.worker = this; } public void run() { thread = channel.workerThread = Thread.currentThread(); while (channel.isOpen()) { synchronized (channel.interestOpsLock) { while (!channel.isReadable()) { try { // notify() is not called at all. // close() and setInterestOps() calls Thread.interrupt() channel.interestOpsLock.wait(); } catch (InterruptedException e) { if (!channel.isOpen()) { break; } } } } boolean cont = false; try { cont = process(); } catch (Throwable t) { boolean readTimeout = t instanceof SocketTimeoutException; if (!readTimeout && !channel.isSocketClosed()) { fireExceptionCaught(channel, t); } if (readTimeout) { // the readTimeout was triggered because of the SO_TIMEOUT, // so just continue with the loop here cont = true; } } finally { processEventQueue(); } if (!cont) { break; } } synchronized (channel.interestOpsLock) { // Setting the workerThread to null will prevent any channel // operations from interrupting this thread from now on. // // // Do this while holding the lock to not race with close(...) or // setInterestOps(...) channel.workerThread = null; } // Clean up. close(channel, succeededFuture(channel), true); // Mark the worker event loop as done so we know that we need to run tasks directly and not queue them // See #287 done = true; // just to make we don't have something left processEventQueue(); } static boolean isIoThread(AbstractOioChannel channel) { return Thread.currentThread() == channel.workerThread; } public void executeInIoThread(Runnable task) { // check if the current thread is the worker thread // // Also check if the event loop of the worker is complete. If so we need to run the task now. // See #287 if (Thread.currentThread() == thread || done) { task.run(); } else { boolean added = eventQueue.offer(task); if (added) { // as we set the SO_TIMEOUT to 1 second this task will get picked up in 1 second at latest } } } private void processEventQueue() { for (;;) { final Runnable task = eventQueue.poll(); if (task == null) { break; } task.run(); } } /** * Process the incoming messages and also is responsible for call * {@link Channels#fireMessageReceived(Channel, Object)} once a message was processed without * errors. * * @return continue returns {@code true} as long as this worker should continue to try * processing incoming messages * @throws IOException */ abstract boolean process() throws IOException; static void setInterestOps( AbstractOioChannel channel, ChannelFuture future, int interestOps) { boolean iothread = isIoThread(channel); // Override OP_WRITE flag - a user cannot change this flag. interestOps &= ~Channel.OP_WRITE; interestOps |= channel.getInterestOps() & Channel.OP_WRITE; boolean changed = false; try { if (channel.getInterestOps() != interestOps) { if ((interestOps & Channel.OP_READ) != 0) { channel.setInterestOpsNow(Channel.OP_READ); } else { channel.setInterestOpsNow(Channel.OP_NONE); } changed = true; } future.setSuccess(); if (changed) { synchronized (channel.interestOpsLock) { channel.setInterestOpsNow(interestOps); // Notify the worker so it stops or continues reading. Thread currentThread = Thread.currentThread(); Thread workerThread = channel.workerThread; if (workerThread != null && currentThread != workerThread) { workerThread.interrupt(); } } if (iothread) { fireChannelInterestChanged(channel); } else { fireChannelInterestChangedLater(channel); } } } catch (Throwable t) { future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } static void close(AbstractOioChannel channel, ChannelFuture future) { close(channel, future, isIoThread(channel)); } private static void close(AbstractOioChannel channel, ChannelFuture future, boolean iothread) { boolean connected = channel.isConnected(); boolean bound = channel.isBound(); try { channel.closeSocket(); if (channel.setClosed()) { future.setSuccess(); if (connected) { Thread currentThread = Thread.currentThread(); synchronized (channel.interestOpsLock) { // We need to do this while hold the lock as otherwise // we may race and so interrupt the workerThread even // if we are in the workerThread now. // This can happen if run() set channel.workerThread to null // between workerThread != null and currentThread!= workerThread Thread workerThread = channel.workerThread; if (workerThread != null && currentThread != workerThread) { workerThread.interrupt(); } } if (iothread) { fireChannelDisconnected(channel); } else { fireChannelDisconnectedLater(channel); } } if (bound) { if (iothread) { fireChannelUnbound(channel); } else { fireChannelUnboundLater(channel); } } if (iothread) { fireChannelClosed(channel); } else { fireChannelClosedLater(channel); } } else { future.setSuccess(); } } catch (Throwable t) { future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } } OioAcceptedSocketChannel.java000066400000000000000000000040721225554127700336750ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import static org.jboss.netty.channel.Channels.*; import java.io.IOException; import java.io.OutputStream; import java.io.PushbackInputStream; import java.net.Socket; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; class OioAcceptedSocketChannel extends OioSocketChannel { private final PushbackInputStream in; private final OutputStream out; OioAcceptedSocketChannel( Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, Socket socket) { super(parent, factory, pipeline, sink, socket); try { in = new PushbackInputStream(socket.getInputStream(), 1); } catch (IOException e) { throw new ChannelException("Failed to obtain an InputStream.", e); } try { out = socket.getOutputStream(); } catch (IOException e) { throw new ChannelException("Failed to obtain an OutputStream.", e); } fireChannelOpen(this); fireChannelBound(this, getLocalAddress()); } @Override PushbackInputStream getInputStream() { return in; } @Override OutputStream getOutputStream() { return out; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/OioClientSocketChannel.java000066400000000000000000000027131225554127700334620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import static org.jboss.netty.channel.Channels.*; import java.io.OutputStream; import java.io.PushbackInputStream; import java.net.Socket; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; class OioClientSocketChannel extends OioSocketChannel { volatile PushbackInputStream in; volatile OutputStream out; OioClientSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(null, factory, pipeline, sink, new Socket()); fireChannelOpen(this); } @Override PushbackInputStream getInputStream() { return in; } @Override OutputStream getOutputStream() { return out; } } OioClientSocketChannelFactory.java000066400000000000000000000113741225554127700347360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.internal.ExecutorUtil; /** * A {@link ClientSocketChannelFactory} which creates a client-side blocking * I/O based {@link SocketChannel}. It utilizes the good old blocking I/O API * which is known to yield better throughput and latency when there are * relatively small number of connections to serve. * *

How threads work

*

* There is only one type of threads in {@link OioClientSocketChannelFactory}; * worker threads. * *

Worker threads

*

* Each connected {@link Channel} has a dedicated worker thread, just like a * traditional blocking I/O thread model. * *

Life cycle of threads and graceful shutdown

*

* Worker threads are acquired from the {@link Executor} which was specified * when a {@link OioClientSocketChannelFactory} was created (i.e. {@code workerExecutor}.) * Therefore, you should make sure the specified {@link Executor} is able to * lend the sufficient number of threads. *

* Worker threads are acquired lazily, and then released when there's nothing * left to process. All the related resources are also released when the * worker threads are released. Therefore, to shut down a service gracefully, * you should do the following: * *

    *
  1. close all channels created by the factory usually using * {@link ChannelGroup#close()}, and
  2. *
  3. call {@link #releaseExternalResources()}.
  4. *
* * Please make sure not to shut down the executor until all channels are * closed. Otherwise, you will end up with a {@link RejectedExecutionException} * and the related resources might not be released properly. * *

Limitation

*

* A {@link SocketChannel} created by this factory does not support asynchronous * operations. Any I/O requests such as {@code "connect"} and {@code "write"} * will be performed in a blocking manner. * * @apiviz.landmark */ public class OioClientSocketChannelFactory implements ClientSocketChannelFactory { private final Executor workerExecutor; final OioClientSocketPipelineSink sink; private boolean shutdownExecutor; /** * Creates a new instance with a {@link Executors#newCachedThreadPool()} as worker executor. * * See {@link #OioClientSocketChannelFactory(Executor)} */ public OioClientSocketChannelFactory() { this(Executors.newCachedThreadPool()); shutdownExecutor = true; } /** * Creates a new instance. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads */ public OioClientSocketChannelFactory(Executor workerExecutor) { this(workerExecutor, null); } /** * Creates a new instance. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param determiner * the {@link ThreadNameDeterminer} to set the thread names. */ public OioClientSocketChannelFactory(Executor workerExecutor, ThreadNameDeterminer determiner) { if (workerExecutor == null) { throw new NullPointerException("workerExecutor"); } this.workerExecutor = workerExecutor; sink = new OioClientSocketPipelineSink(workerExecutor, determiner); } public SocketChannel newChannel(ChannelPipeline pipeline) { return new OioClientSocketChannel(this, pipeline, sink); } public void shutdown() { if (shutdownExecutor) { ExecutorUtil.shutdownNow(workerExecutor); } } public void releaseExternalResources() { shutdown(); ExecutorUtil.shutdownNow(workerExecutor); } } OioClientSocketPipelineSink.java000066400000000000000000000126111225554127700344230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import org.jboss.netty.util.internal.DeadLockProofWorker; import java.io.PushbackInputStream; import java.net.ConnectException; import java.net.SocketAddress; import java.util.concurrent.Executor; import static org.jboss.netty.channel.Channels.*; class OioClientSocketPipelineSink extends AbstractOioChannelSink { private final Executor workerExecutor; private final ThreadNameDeterminer determiner; OioClientSocketPipelineSink(Executor workerExecutor, ThreadNameDeterminer determiner) { this.workerExecutor = workerExecutor; this.determiner = determiner; } public void eventSunk( ChannelPipeline pipeline, ChannelEvent e) throws Exception { OioClientSocketChannel channel = (OioClientSocketChannel) e.getChannel(); ChannelFuture future = e.getFuture(); if (e instanceof ChannelStateEvent) { ChannelStateEvent stateEvent = (ChannelStateEvent) e; ChannelState state = stateEvent.getState(); Object value = stateEvent.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { AbstractOioWorker.close(channel, future); } break; case BOUND: if (value != null) { bind(channel, future, (SocketAddress) value); } else { AbstractOioWorker.close(channel, future); } break; case CONNECTED: if (value != null) { connect(channel, future, (SocketAddress) value); } else { AbstractOioWorker.close(channel, future); } break; case INTEREST_OPS: AbstractOioWorker.setInterestOps(channel, future, ((Integer) value).intValue()); break; } } else if (e instanceof MessageEvent) { OioWorker.write( channel, future, ((MessageEvent) e).getMessage()); } } private static void bind( OioClientSocketChannel channel, ChannelFuture future, SocketAddress localAddress) { try { channel.socket.bind(localAddress); future.setSuccess(); fireChannelBound(channel, channel.getLocalAddress()); } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } private void connect( OioClientSocketChannel channel, ChannelFuture future, SocketAddress remoteAddress) { boolean bound = channel.isBound(); boolean connected = false; boolean workerStarted = false; future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); try { channel.socket.connect( remoteAddress, channel.getConfig().getConnectTimeoutMillis()); connected = true; // Obtain I/O stream. channel.in = new PushbackInputStream(channel.socket.getInputStream(), 1); channel.out = channel.socket.getOutputStream(); // Fire events. future.setSuccess(); if (!bound) { fireChannelBound(channel, channel.getLocalAddress()); } fireChannelConnected(channel, channel.getRemoteAddress()); // Start the business. DeadLockProofWorker.start( workerExecutor, new ThreadRenamingRunnable( new OioWorker(channel), "Old I/O client worker (" + channel + ')', determiner)); workerStarted = true; } catch (Throwable t) { if (t instanceof ConnectException) { if (t instanceof ConnectException) { Throwable newT = new ConnectException(t.getMessage() + ": " + remoteAddress); newT.setStackTrace(t.getStackTrace()); t = newT; } } future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (connected && !workerStarted) { AbstractOioWorker.close(channel, future); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/OioDatagramChannel.java000066400000000000000000000105571225554127700326200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannelConfig; import org.jboss.netty.channel.socket.DefaultDatagramChannelConfig; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.SocketException; import static org.jboss.netty.channel.Channels.*; final class OioDatagramChannel extends AbstractOioChannel implements DatagramChannel { final MulticastSocket socket; private final DatagramChannelConfig config; OioDatagramChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(null, factory, pipeline, sink); try { socket = new MulticastSocket(null); } catch (IOException e) { throw new ChannelException("Failed to open a datagram socket.", e); } try { socket.setSoTimeout(10); socket.setBroadcast(false); } catch (SocketException e) { throw new ChannelException( "Failed to configure the datagram socket timeout.", e); } config = new DefaultDatagramChannelConfig(socket); fireChannelOpen(this); } public DatagramChannelConfig getConfig() { return config; } public ChannelFuture joinGroup(InetAddress multicastAddress) { ensureBound(); try { socket.joinGroup(multicastAddress); return succeededFuture(this); } catch (IOException e) { return failedFuture(this, e); } } public ChannelFuture joinGroup( InetSocketAddress multicastAddress, NetworkInterface networkInterface) { ensureBound(); try { socket.joinGroup(multicastAddress, networkInterface); return succeededFuture(this); } catch (IOException e) { return failedFuture(this, e); } } private void ensureBound() { if (!isBound()) { throw new IllegalStateException( DatagramChannel.class.getName() + " must be bound to join a group."); } } public ChannelFuture leaveGroup(InetAddress multicastAddress) { try { socket.leaveGroup(multicastAddress); return succeededFuture(this); } catch (IOException e) { return failedFuture(this, e); } } public ChannelFuture leaveGroup( InetSocketAddress multicastAddress, NetworkInterface networkInterface) { try { socket.leaveGroup(multicastAddress, networkInterface); return succeededFuture(this); } catch (IOException e) { return failedFuture(this, e); } } @Override boolean isSocketBound() { return socket.isBound(); } @Override boolean isSocketConnected() { return socket.isConnected(); } @Override InetSocketAddress getLocalSocketAddress() throws Exception { return (InetSocketAddress) socket.getLocalSocketAddress(); } @Override InetSocketAddress getRemoteSocketAddress() throws Exception { return (InetSocketAddress) socket.getRemoteSocketAddress(); } @Override void closeSocket() { socket.close(); } @Override boolean isSocketClosed() { return socket.isClosed(); } } OioDatagramChannelFactory.java000066400000000000000000000110641225554127700340630ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannelFactory; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.internal.ExecutorUtil; /** * A {@link DatagramChannelFactory} which creates a blocking I/O based * {@link DatagramChannel}. It utilizes the good old blocking I/O API which * has support for multicast. * *

How threads work

*

* There is only one type of threads in {@link OioDatagramChannelFactory}; * worker threads. * *

Worker threads

*

* Each {@link Channel} has a dedicated worker thread, just like a * traditional blocking I/O thread model. * *

Life cycle of threads and graceful shutdown

*

* Worker threads are acquired from the {@link Executor} which was specified * when a {@link OioDatagramChannelFactory} was created (i.e. {@code workerExecutor}.) * Therefore, you should make sure the specified {@link Executor} is able to * lend the sufficient number of threads. *

* Worker threads are acquired lazily, and then released when there's nothing * left to process. All the related resources are also released when the * worker threads are released. Therefore, to shut down a service gracefully, * you should do the following: * *

    *
  1. close all channels created by the factory usually using * {@link ChannelGroup#close()}, and
  2. *
  3. call {@link #releaseExternalResources()}.
  4. *
* * Please make sure not to shut down the executor until all channels are * closed. Otherwise, you will end up with a {@link RejectedExecutionException} * and the related resources might not be released properly. * *

Limitation

*

* A {@link DatagramChannel} created by this factory does not support asynchronous * operations. Any I/O requests such as {@code "write"} will be performed in a * blocking manner. * * @apiviz.landmark */ public class OioDatagramChannelFactory implements DatagramChannelFactory { private final Executor workerExecutor; final OioDatagramPipelineSink sink; private boolean shutdownExecutor; /** * Creates a new instance with a {@link Executors#newCachedThreadPool()} * * See {@link #OioDatagramChannelFactory(Executor)} */ public OioDatagramChannelFactory() { this(Executors.newCachedThreadPool()); shutdownExecutor = true; } /** * Creates a new instance. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads */ public OioDatagramChannelFactory(Executor workerExecutor) { this(workerExecutor, null); } /** * Creates a new instance. * * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param determiner * the {@link ThreadNameDeterminer} to set the thread names. */ public OioDatagramChannelFactory(Executor workerExecutor, ThreadNameDeterminer determiner) { if (workerExecutor == null) { throw new NullPointerException("workerExecutor"); } this.workerExecutor = workerExecutor; sink = new OioDatagramPipelineSink(workerExecutor, determiner); } public DatagramChannel newChannel(ChannelPipeline pipeline) { return new OioDatagramChannel(this, pipeline, sink); } public void shutdown() { if (shutdownExecutor) { ExecutorUtil.shutdownNow(workerExecutor); } } public void releaseExternalResources() { shutdown(); ExecutorUtil.shutdownNow(workerExecutor); } } OioDatagramPipelineSink.java000066400000000000000000000137501225554127700335610ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import static org.jboss.netty.channel.Channels.*; import java.net.SocketAddress; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import org.jboss.netty.util.internal.DeadLockProofWorker; class OioDatagramPipelineSink extends AbstractOioChannelSink { private final Executor workerExecutor; private final ThreadNameDeterminer determiner; OioDatagramPipelineSink(Executor workerExecutor, ThreadNameDeterminer determiner) { this.workerExecutor = workerExecutor; this.determiner = determiner; } public void eventSunk( ChannelPipeline pipeline, ChannelEvent e) throws Exception { OioDatagramChannel channel = (OioDatagramChannel) e.getChannel(); ChannelFuture future = e.getFuture(); if (e instanceof ChannelStateEvent) { ChannelStateEvent stateEvent = (ChannelStateEvent) e; ChannelState state = stateEvent.getState(); Object value = stateEvent.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { AbstractOioWorker.close(channel, future); } break; case BOUND: if (value != null) { bind(channel, future, (SocketAddress) value); } else { AbstractOioWorker.close(channel, future); } break; case CONNECTED: if (value != null) { connect(channel, future, (SocketAddress) value); } else { OioDatagramWorker.disconnect(channel, future); } break; case INTEREST_OPS: AbstractOioWorker.setInterestOps(channel, future, ((Integer) value).intValue()); break; } } else if (e instanceof MessageEvent) { MessageEvent evt = (MessageEvent) e; OioDatagramWorker.write( channel, future, evt.getMessage(), evt.getRemoteAddress()); } } private void bind( OioDatagramChannel channel, ChannelFuture future, SocketAddress localAddress) { boolean bound = false; boolean workerStarted = false; try { channel.socket.bind(localAddress); bound = true; // Fire events future.setSuccess(); fireChannelBound(channel, channel.getLocalAddress()); // Start the business. DeadLockProofWorker.start( workerExecutor, new ThreadRenamingRunnable( new OioDatagramWorker(channel), "Old I/O datagram worker (" + channel + ')', determiner)); workerStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (bound && !workerStarted) { AbstractOioWorker.close(channel, future); } } } private void connect( OioDatagramChannel channel, ChannelFuture future, SocketAddress remoteAddress) { boolean bound = channel.isBound(); boolean connected = false; boolean workerStarted = false; future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); // Clear the cached address so that the next getRemoteAddress() call // updates the cache. channel.remoteAddress = null; try { channel.socket.connect(remoteAddress); connected = true; // Fire events. future.setSuccess(); if (!bound) { fireChannelBound(channel, channel.getLocalAddress()); } fireChannelConnected(channel, channel.getRemoteAddress()); String threadName = "Old I/O datagram worker (" + channel + ')'; if (!bound) { // Start the business. DeadLockProofWorker.start( workerExecutor, new ThreadRenamingRunnable( new OioDatagramWorker(channel), threadName, determiner)); } else { // Worker started by bind() - just rename. Thread workerThread = channel.workerThread; if (workerThread != null) { try { workerThread.setName(threadName); } catch (SecurityException e) { // Ignore. } } } workerStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (connected && !workerStarted) { AbstractOioWorker.close(channel, future); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/OioDatagramWorker.java000066400000000000000000000102451225554127700325130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ReceiveBufferSizePredictor; import java.io.IOException; import java.io.InterruptedIOException; import java.net.DatagramPacket; import java.net.SocketAddress; import java.nio.ByteBuffer; import static org.jboss.netty.channel.Channels.*; class OioDatagramWorker extends AbstractOioWorker { OioDatagramWorker(OioDatagramChannel channel) { super(channel); } @Override boolean process() throws IOException { ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor(); byte[] buf = new byte[predictor.nextReceiveBufferSize()]; DatagramPacket packet = new DatagramPacket(buf, buf.length); try { channel.socket.receive(packet); } catch (InterruptedIOException e) { // Can happen on interruption. // Keep receiving unless the channel is closed. return true; } fireMessageReceived( channel, channel.getConfig().getBufferFactory().getBuffer(buf, 0, packet.getLength()), packet.getSocketAddress()); return true; } static void write( OioDatagramChannel channel, ChannelFuture future, Object message, SocketAddress remoteAddress) { boolean iothread = isIoThread(channel); try { ChannelBuffer buf = (ChannelBuffer) message; int offset = buf.readerIndex(); int length = buf.readableBytes(); ByteBuffer nioBuf = buf.toByteBuffer(); DatagramPacket packet; if (nioBuf.hasArray()) { // Avoid copy if the buffer is backed by an array. packet = new DatagramPacket( nioBuf.array(), nioBuf.arrayOffset() + offset, length); } else { // Otherwise it will be expensive. byte[] arrayBuf = new byte[length]; buf.getBytes(0, arrayBuf); packet = new DatagramPacket(arrayBuf, length); } if (remoteAddress != null) { packet.setSocketAddress(remoteAddress); } channel.socket.send(packet); if (iothread) { fireWriteComplete(channel, length); } else { fireWriteCompleteLater(channel, length); } future.setSuccess(); } catch (Throwable t) { future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } static void disconnect(OioDatagramChannel channel, ChannelFuture future) { boolean connected = channel.isConnected(); boolean iothread = isIoThread(channel); try { channel.socket.disconnect(); future.setSuccess(); if (connected) { // Notify. if (iothread) { fireChannelDisconnected(channel); } else { fireChannelDisconnectedLater(channel); } } } catch (Throwable t) { future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/OioServerSocketChannel.java000066400000000000000000000062721225554127700335160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import static org.jboss.netty.channel.Channels.*; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.jboss.netty.channel.AbstractServerChannel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.socket.DefaultServerSocketChannelConfig; import org.jboss.netty.channel.socket.ServerSocketChannel; import org.jboss.netty.channel.socket.ServerSocketChannelConfig; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; class OioServerSocketChannel extends AbstractServerChannel implements ServerSocketChannel { private static final InternalLogger logger = InternalLoggerFactory.getInstance(OioServerSocketChannel.class); final ServerSocket socket; final Lock shutdownLock = new ReentrantLock(); private final ServerSocketChannelConfig config; OioServerSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(factory, pipeline, sink); try { socket = new ServerSocket(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } try { socket.setSoTimeout(1000); } catch (IOException e) { try { socket.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e2); } } throw new ChannelException( "Failed to set the server socket timeout.", e); } config = new DefaultServerSocketChannelConfig(socket); fireChannelOpen(this); } public ServerSocketChannelConfig getConfig() { return config; } public InetSocketAddress getLocalAddress() { return (InetSocketAddress) socket.getLocalSocketAddress(); } public InetSocketAddress getRemoteAddress() { return null; } public boolean isBound() { return isOpen() && socket.isBound(); } @Override protected boolean setClosed() { return super.setClosed(); } } OioServerSocketChannelFactory.java000066400000000000000000000140421225554127700347610ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.ServerSocketChannel; import org.jboss.netty.channel.socket.ServerSocketChannelFactory; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.internal.ExecutorUtil; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; /** * A {@link ServerSocketChannelFactory} which creates a server-side blocking * I/O based {@link ServerSocketChannel}. It utilizes the good old blocking * I/O API which is known to yield better throughput and latency when there * are relatively small number of connections to serve. * *

How threads work

*

* There are two types of threads in a {@link OioServerSocketChannelFactory}; * one is boss thread and the other is worker thread. * *

Boss threads

*

* Each bound {@link ServerSocketChannel} has its own boss thread. * For example, if you opened two server ports such as 80 and 443, you will * have two boss threads. A boss thread accepts incoming connections until * the port is unbound. Once a connection is accepted successfully, the boss * thread passes the accepted {@link Channel} to one of the worker * threads that the {@link OioServerSocketChannelFactory} manages. * *

Worker threads

*

* Each connected {@link Channel} has a dedicated worker thread, just like a * traditional blocking I/O thread model. * *

Life cycle of threads and graceful shutdown

*

* All threads are acquired from the {@link Executor}s which were specified * when a {@link OioServerSocketChannelFactory} was created. Boss threads are * acquired from the {@code bossExecutor}, and worker threads are acquired from * the {@code workerExecutor}. Therefore, you should make sure the specified * {@link Executor}s are able to lend the sufficient number of threads. *

* Both boss and worker threads are acquired lazily, and then released when * there's nothing left to process. All the related resources are also * released when the boss and worker threads are released. Therefore, to shut * down a service gracefully, you should do the following: * *

    *
  1. unbind all channels created by the factory, *
  2. close all child channels accepted by the unbound channels, * (these two steps so far is usually done using {@link ChannelGroup#close()})
  3. *
  4. call {@link #releaseExternalResources()}.
  5. *
* * Please make sure not to shut down the executor until all channels are * closed. Otherwise, you will end up with a {@link RejectedExecutionException} * and the related resources might not be released properly. * *

Limitation

*

* A {@link ServerSocketChannel} created by this factory and its child channels * do not support asynchronous operations. Any I/O requests such as * {@code "write"} will be performed in a blocking manner. * * @apiviz.landmark */ public class OioServerSocketChannelFactory implements ServerSocketChannelFactory { final Executor bossExecutor; private final Executor workerExecutor; private final ChannelSink sink; private boolean shutdownExecutor; /** * Create a new {@link OioServerSocketChannelFactory} with a {@link Executors#newCachedThreadPool()} * for the boss and worker executor. * * See {@link #OioServerSocketChannelFactory(Executor, Executor)} */ public OioServerSocketChannelFactory() { this(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); shutdownExecutor = true; } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads */ public OioServerSocketChannelFactory( Executor bossExecutor, Executor workerExecutor) { this(bossExecutor, workerExecutor, null); } /** * Creates a new instance. * * @param bossExecutor * the {@link Executor} which will execute the boss threads * @param workerExecutor * the {@link Executor} which will execute the I/O worker threads * @param determiner * the {@link ThreadNameDeterminer} to set the thread names. */ public OioServerSocketChannelFactory(Executor bossExecutor, Executor workerExecutor, ThreadNameDeterminer determiner) { if (bossExecutor == null) { throw new NullPointerException("bossExecutor"); } if (workerExecutor == null) { throw new NullPointerException("workerExecutor"); } this.bossExecutor = bossExecutor; this.workerExecutor = workerExecutor; sink = new OioServerSocketPipelineSink(workerExecutor, determiner); } public ServerSocketChannel newChannel(ChannelPipeline pipeline) { return new OioServerSocketChannel(this, pipeline, sink); } public void shutdown() { if (shutdownExecutor) { ExecutorUtil.shutdownNow(workerExecutor); } } public void releaseExternalResources() { shutdown(); ExecutorUtil.shutdownNow(workerExecutor); } } OioServerSocketPipelineSink.java000066400000000000000000000231301225554127700344510ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import static org.jboss.netty.channel.Channels.*; import java.io.IOException; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.util.concurrent.Executor; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.ThreadRenamingRunnable; import org.jboss.netty.util.internal.DeadLockProofWorker; class OioServerSocketPipelineSink extends AbstractOioChannelSink { static final InternalLogger logger = InternalLoggerFactory.getInstance(OioServerSocketPipelineSink.class); final Executor workerExecutor; private final ThreadNameDeterminer determiner; OioServerSocketPipelineSink(Executor workerExecutor, ThreadNameDeterminer determiner) { this.workerExecutor = workerExecutor; this.determiner = determiner; } public void eventSunk( ChannelPipeline pipeline, ChannelEvent e) throws Exception { Channel channel = e.getChannel(); if (channel instanceof OioServerSocketChannel) { handleServerSocket(e); } else if (channel instanceof OioAcceptedSocketChannel) { handleAcceptedSocket(e); } } private void handleServerSocket(ChannelEvent e) { if (!(e instanceof ChannelStateEvent)) { return; } ChannelStateEvent event = (ChannelStateEvent) e; OioServerSocketChannel channel = (OioServerSocketChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { close(channel, future); } break; case BOUND: if (value != null) { bind(channel, future, (SocketAddress) value); } else { close(channel, future); } break; } } private static void handleAcceptedSocket(ChannelEvent e) { if (e instanceof ChannelStateEvent) { ChannelStateEvent event = (ChannelStateEvent) e; OioAcceptedSocketChannel channel = (OioAcceptedSocketChannel) event.getChannel(); ChannelFuture future = event.getFuture(); ChannelState state = event.getState(); Object value = event.getValue(); switch (state) { case OPEN: if (Boolean.FALSE.equals(value)) { AbstractOioWorker.close(channel, future); } break; case BOUND: case CONNECTED: if (value == null) { AbstractOioWorker.close(channel, future); } break; case INTEREST_OPS: AbstractOioWorker.setInterestOps(channel, future, ((Integer) value).intValue()); break; } } else if (e instanceof MessageEvent) { MessageEvent event = (MessageEvent) e; OioSocketChannel channel = (OioSocketChannel) event.getChannel(); ChannelFuture future = event.getFuture(); Object message = event.getMessage(); OioWorker.write(channel, future, message); } } private void bind( OioServerSocketChannel channel, ChannelFuture future, SocketAddress localAddress) { boolean bound = false; boolean bossStarted = false; try { channel.socket.bind(localAddress, channel.getConfig().getBacklog()); bound = true; future.setSuccess(); localAddress = channel.getLocalAddress(); fireChannelBound(channel, localAddress); Executor bossExecutor = ((OioServerSocketChannelFactory) channel.getFactory()).bossExecutor; DeadLockProofWorker.start( bossExecutor, new ThreadRenamingRunnable( new Boss(channel), "Old I/O server boss (" + channel + ')', determiner)); bossStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (!bossStarted && bound) { close(channel, future); } } } private static void close(OioServerSocketChannel channel, ChannelFuture future) { boolean bound = channel.isBound(); try { channel.socket.close(); // Make sure the boss thread is not running so that that the future // is notified after a new connection cannot be accepted anymore. // See NETTY-256 for more information. channel.shutdownLock.lock(); try { if (channel.setClosed()) { future.setSuccess(); if (bound) { fireChannelUnbound(channel); } fireChannelClosed(channel); } else { future.setSuccess(); } } finally { channel.shutdownLock.unlock(); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } } private final class Boss implements Runnable { private final OioServerSocketChannel channel; Boss(OioServerSocketChannel channel) { this.channel = channel; } public void run() { channel.shutdownLock.lock(); try { while (channel.isBound()) { try { Socket acceptedSocket = channel.socket.accept(); try { ChannelPipeline pipeline = channel.getConfig().getPipelineFactory().getPipeline(); final OioAcceptedSocketChannel acceptedChannel = new OioAcceptedSocketChannel( channel, channel.getFactory(), pipeline, OioServerSocketPipelineSink.this, acceptedSocket); DeadLockProofWorker.start( workerExecutor, new ThreadRenamingRunnable( new OioWorker(acceptedChannel), "Old I/O server worker (parentId: " + channel.getId() + ", " + channel + ')', determiner)); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn( "Failed to initialize an accepted socket.", e); } try { acceptedSocket.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially accepted socket.", e2); } } } } catch (SocketTimeoutException e) { // Thrown every second to stop when requested. } catch (Throwable e) { // Do not log the exception if the server socket was closed // by a user. if (!channel.socket.isBound() || channel.socket.isClosed()) { break; } if (logger.isWarnEnabled()) { logger.warn( "Failed to accept a connection.", e); } try { Thread.sleep(1000); } catch (InterruptedException e1) { // Ignore } } } } finally { channel.shutdownLock.unlock(); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/OioSocketChannel.java000066400000000000000000000054401225554127700323230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import java.io.IOException; import java.io.OutputStream; import java.io.PushbackInputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.socket.DefaultSocketChannelConfig; import org.jboss.netty.channel.socket.SocketChannel; import org.jboss.netty.channel.socket.SocketChannelConfig; abstract class OioSocketChannel extends AbstractOioChannel implements SocketChannel { final Socket socket; private final SocketChannelConfig config; OioSocketChannel( Channel parent, ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink, Socket socket) { super(parent, factory, pipeline, sink); this.socket = socket; try { socket.setSoTimeout(1000); } catch (SocketException e) { throw new ChannelException( "Failed to configure the OioSocketChannel socket timeout.", e); } config = new DefaultSocketChannelConfig(socket); } public SocketChannelConfig getConfig() { return config; } abstract PushbackInputStream getInputStream(); abstract OutputStream getOutputStream(); @Override boolean isSocketBound() { return socket.isBound(); } @Override boolean isSocketConnected() { return socket.isConnected(); } @Override InetSocketAddress getLocalSocketAddress() throws Exception { return (InetSocketAddress) socket.getLocalSocketAddress(); } @Override InetSocketAddress getRemoteSocketAddress() throws Exception { return (InetSocketAddress) socket.getRemoteSocketAddress(); } @Override void closeSocket() throws IOException { socket.close(); } @Override boolean isSocketClosed() { return socket.isClosed(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/OioWorker.java000066400000000000000000000121051225554127700310470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.oio; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.DefaultFileRegion; import org.jboss.netty.channel.FileRegion; import java.io.IOException; import java.io.OutputStream; import java.io.PushbackInputStream; import java.net.SocketException; import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; import java.nio.channels.WritableByteChannel; import java.util.regex.Pattern; import static org.jboss.netty.channel.Channels.*; class OioWorker extends AbstractOioWorker { private static final Pattern SOCKET_CLOSED_MESSAGE = Pattern.compile( "^.*(?:Socket.*closed).*$", Pattern.CASE_INSENSITIVE); OioWorker(OioSocketChannel channel) { super(channel); } @Override public void run() { boolean fireConnected = channel instanceof OioAcceptedSocketChannel; if (fireConnected && channel.isOpen()) { // Fire the channelConnected event for OioAcceptedSocketChannel. // See #287 fireChannelConnected(channel, channel.getRemoteAddress()); } super.run(); } @Override boolean process() throws IOException { byte[] buf; int readBytes; PushbackInputStream in = channel.getInputStream(); int bytesToRead = in.available(); if (bytesToRead > 0) { buf = new byte[bytesToRead]; readBytes = in.read(buf); } else { int b = in.read(); if (b < 0) { return false; } in.unread(b); return true; } fireMessageReceived(channel, channel.getConfig().getBufferFactory().getBuffer(buf, 0, readBytes)); return true; } static void write( OioSocketChannel channel, ChannelFuture future, Object message) { boolean iothread = isIoThread(channel); OutputStream out = channel.getOutputStream(); if (out == null) { Exception e = new ClosedChannelException(); future.setFailure(e); if (iothread) { fireExceptionCaught(channel, e); } else { fireExceptionCaughtLater(channel, e); } return; } try { int length = 0; // Add support to write a FileRegion. This in fact will not give any performance gain // but at least it not fail and we did the best to emulate it if (message instanceof FileRegion) { FileRegion fr = (FileRegion) message; try { synchronized (out) { WritableByteChannel bchannel = Channels.newChannel(out); long i; while ((i = fr.transferTo(bchannel, length)) > 0) { length += i; if (length >= fr.getCount()) { break; } } } } finally { if (fr instanceof DefaultFileRegion) { DefaultFileRegion dfr = (DefaultFileRegion) fr; if (dfr.releaseAfterTransfer()) { fr.releaseExternalResources(); } } } } else { ChannelBuffer a = (ChannelBuffer) message; length = a.readableBytes(); synchronized (out) { a.getBytes(a.readerIndex(), out, length); } } future.setSuccess(); if (iothread) { fireWriteComplete(channel, length); } else { fireWriteCompleteLater(channel, length); } } catch (Throwable t) { // Convert 'SocketException: Socket closed' to // ClosedChannelException. if (t instanceof SocketException && SOCKET_CLOSED_MESSAGE.matcher( String.valueOf(t.getMessage())).matches()) { t = new ClosedChannelException(); } future.setFailure(t); if (iothread) { fireExceptionCaught(channel, t); } else { fireExceptionCaughtLater(channel, t); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/oio/package-info.java000066400000000000000000000014541225554127700314600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Old blocking I/O based socket channel API implementation - recommended for * a small number of connections (< 1000). */ package org.jboss.netty.channel.socket.oio; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/channel/socket/package-info.java000066400000000000000000000015611225554127700306710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Abstract TCP and UDP socket interfaces which extend the core channel API. * * @apiviz.exclude \.(Abstract|Default).*$ * @apiviz.exclude \.socket\.[a-z]+\. * @apiviz.exclude \.channel\.[A-Z] */ package org.jboss.netty.channel.socket; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/000077500000000000000000000000001225554127700245615ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/microcontainer/000077500000000000000000000000001225554127700275755ustar00rootroot00000000000000NettyLoggerConfigurator.java000066400000000000000000000020061225554127700352050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/microcontainer/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.container.microcontainer; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.logging.JBossLoggerFactory; /** * A bean that configures the default {@link InternalLoggerFactory}. */ public class NettyLoggerConfigurator { public NettyLoggerConfigurator() { InternalLoggerFactory.setDefaultFactory(new JBossLoggerFactory()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/microcontainer/package-info.java000066400000000000000000000014351225554127700327670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * JBoss Microcontainer integration. * * @apiviz.exclude */ package org.jboss.netty.container.microcontainer; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/osgi/000077500000000000000000000000001225554127700255225ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/osgi/NettyBundleActivator.java000066400000000000000000000030231225554127700324750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.container.osgi; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.logging.OsgiLoggerFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; /** * An OSGi {@link BundleActivator} that configures logging. */ public class NettyBundleActivator implements BundleActivator { private OsgiLoggerFactory loggerFactory; public void start(BundleContext ctx) throws Exception { // Switch the internal logger to the OSGi LogService. loggerFactory = new OsgiLoggerFactory(ctx); InternalLoggerFactory.setDefaultFactory(loggerFactory); } public void stop(BundleContext ctx) throws Exception { if (loggerFactory != null) { InternalLoggerFactory.setDefaultFactory(loggerFactory.getFallback()); loggerFactory.destroy(); loggerFactory = null; } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/osgi/package-info.java000066400000000000000000000014041225554127700307100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * OSGi framework integration. * * @apiviz.exclude */ package org.jboss.netty.container.osgi; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/spring/000077500000000000000000000000001225554127700260635ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/spring/NettyLoggerConfigurator.java000066400000000000000000000020021225554127700335460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.container.spring; import org.jboss.netty.logging.CommonsLoggerFactory; import org.jboss.netty.logging.InternalLoggerFactory; /** * A bean that configures the default {@link InternalLoggerFactory}. */ public class NettyLoggerConfigurator { public NettyLoggerConfigurator() { InternalLoggerFactory.setDefaultFactory(new CommonsLoggerFactory()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/container/spring/package-info.java000066400000000000000000000014231225554127700312520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Spring framework integration. * * @apiviz.exclude */ package org.jboss.netty.container.spring; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/000077500000000000000000000000001225554127700242325ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/discard/000077500000000000000000000000001225554127700256435ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/discard/DiscardClient.java000066400000000000000000000061101225554127700312140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.discard; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; /** * Keeps sending random data to the specified address. */ public class DiscardClient { private final String host; private final int port; private final int firstMessageSize; public DiscardClient(String host, int port, int firstMessageSize) { this.host = host; this.port = port; this.firstMessageSize = firstMessageSize; } public void run() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new DiscardClientHandler(firstMessageSize)); } }); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection is closed or the connection attempt fails. future.getChannel().getCloseFuture().awaitUninterruptibly(); // Shut down thread pools to exit. bootstrap.releaseExternalResources(); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { System.err.println( "Usage: " + DiscardClient.class.getSimpleName() + " []"); return; } // Parse options. final String host = args[0]; final int port = Integer.parseInt(args[1]); final int firstMessageSize; if (args.length == 3) { firstMessageSize = Integer.parseInt(args[2]); } else { firstMessageSize = 256; } new DiscardClient(host, port, firstMessageSize).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/discard/DiscardClientHandler.java000066400000000000000000000076621225554127700325270ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.discard; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.WriteCompletionEvent; /** * Handles a client-side channel. */ public class DiscardClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( DiscardClientHandler.class.getName()); private long transferredBytes; private final byte[] content; public DiscardClientHandler(int messageSize) { if (messageSize <= 0) { throw new IllegalArgumentException( "messageSize: " + messageSize); } content = new byte[messageSize]; } public long getTransferredBytes() { return transferredBytes; } @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { if (((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) { logger.info(e.toString()); } } // Let SimpleChannelHandler call actual event handler methods below. super.handleUpstream(ctx, e); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { // Send the initial messages. generateTraffic(e); } @Override public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) { // Keep sending messages whenever the current socket buffer has room. generateTraffic(e); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { // Server is supposed to send nothing. Therefore, do nothing. } @Override public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) { transferredBytes += e.getWrittenAmount(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { // Close the connection when an exception is raised. logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } private void generateTraffic(ChannelStateEvent e) { // Keep generating traffic until the channel is unwritable. // A channel becomes unwritable when its internal buffer is full. // If you keep writing messages ignoring this property, // you will end up with an OutOfMemoryError. Channel channel = e.getChannel(); while (channel.isWritable()) { ChannelBuffer m = nextMessage(); if (m == null) { break; } channel.write(m); } } private ChannelBuffer nextMessage() { return ChannelBuffers.wrappedBuffer(content); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/discard/DiscardServer.java000066400000000000000000000041051225554127700312460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.discard; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * Discards any incoming data. */ public class DiscardServer { private final int port; public DiscardServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new DiscardServerHandler()); } }); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new DiscardServer(port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/discard/DiscardServerHandler.java000066400000000000000000000044301225554127700325450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.discard; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handles a server-side channel. */ public class DiscardServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( DiscardServerHandler.class.getName()); private long transferredBytes; public long getTransferredBytes() { return transferredBytes; } @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } // Let SimpleChannelHandler call actual event handler methods below. super.handleUpstream(ctx, e); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { // Discard received data silently by doing nothing. transferredBytes += ((ChannelBuffer) e.getMessage()).readableBytes(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { // Close the connection when an exception is raised. logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/echo/000077500000000000000000000000001225554127700251505ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/echo/EchoClient.java000066400000000000000000000063641225554127700300410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.echo; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; /** * Sends one message when a connection is open and echoes back any received * data to the server. Simply put, the echo client initiates the ping-pong * traffic between the echo client and server by sending the first message to * the server. */ public class EchoClient { private final String host; private final int port; private final int firstMessageSize; public EchoClient(String host, int port, int firstMessageSize) { this.host = host; this.port = port; this.firstMessageSize = firstMessageSize; } public void run() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new EchoClientHandler(firstMessageSize)); } }); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection is closed or the connection attempt fails. future.getChannel().getCloseFuture().awaitUninterruptibly(); // Shut down thread pools to exit. bootstrap.releaseExternalResources(); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { System.err.println( "Usage: " + EchoClient.class.getSimpleName() + " []"); return; } // Parse options. final String host = args[0]; final int port = Integer.parseInt(args[1]); final int firstMessageSize; if (args.length == 3) { firstMessageSize = Integer.parseInt(args[2]); } else { firstMessageSize = 256; } new EchoClient(host, port, firstMessageSize).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/echo/EchoClientHandler.java000066400000000000000000000060061225554127700313300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.echo; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handler implementation for the echo client. It initiates the ping-pong * traffic between the echo client and server by sending the first message to * the server. */ public class EchoClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( EchoClientHandler.class.getName()); private final ChannelBuffer firstMessage; private final AtomicLong transferredBytes = new AtomicLong(); /** * Creates a client-side handler. */ public EchoClientHandler(int firstMessageSize) { if (firstMessageSize <= 0) { throw new IllegalArgumentException( "firstMessageSize: " + firstMessageSize); } firstMessage = ChannelBuffers.buffer(firstMessageSize); for (int i = 0; i < firstMessage.capacity(); i ++) { firstMessage.writeByte((byte) i); } } public long getTransferredBytes() { return transferredBytes.get(); } @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) { // Send the first message. Server will not send anything here // because the firstMessage's capacity is 0. e.getChannel().write(firstMessage); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Send back the received message to the remote peer. transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes()); e.getChannel().write(e.getMessage()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { // Close the connection when an exception is raised. logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/echo/EchoServer.java000066400000000000000000000041071225554127700300620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.echo; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * Echoes back any received data from a client. */ public class EchoServer { private final int port; public EchoServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new EchoServerHandler()); } }); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new EchoServer(port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/echo/EchoServerHandler.java000066400000000000000000000040361225554127700313610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.echo; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handler implementation for the echo server. */ public class EchoServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( EchoServerHandler.class.getName()); private final AtomicLong transferredBytes = new AtomicLong(); public long getTransferredBytes() { return transferredBytes.get(); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Send back the received message to the remote peer. transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes()); e.getChannel().write(e.getMessage()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { // Close the connection when an exception is raised. logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/000077500000000000000000000000001225554127700261765ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/BigIntegerDecoder.java000066400000000000000000000043751225554127700323570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import java.math.BigInteger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.CorruptedFrameException; import org.jboss.netty.handler.codec.frame.FrameDecoder; /** * Decodes the binary representation of a {@link BigInteger} prepended * with a magic number ('F' or 0x46) and a 32-bit integer length prefix into a * {@link BigInteger} instance. For example, { 'F', 0, 0, 0, 1, 42 } will be * decoded into new BigInteger("42"). */ public class BigIntegerDecoder extends FrameDecoder { @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { // Wait until the length prefix is available. if (buffer.readableBytes() < 5) { return null; } buffer.markReaderIndex(); // Check the magic number. int magicNumber = buffer.readUnsignedByte(); if (magicNumber != 'F') { buffer.resetReaderIndex(); throw new CorruptedFrameException( "Invalid magic number: " + magicNumber); } // Wait until the whole data is available. int dataLength = buffer.readInt(); if (buffer.readableBytes() < dataLength) { buffer.resetReaderIndex(); return null; } // Convert the received data into a new BigInteger. byte[] decoded = new byte[dataLength]; buffer.readBytes(decoded); return new BigInteger(decoded); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/FactorialClient.java000066400000000000000000000060551225554127700321120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; /** * Sends a sequence of integers to a {@link FactorialServer} to calculate * the factorial of the specified integer. */ public class FactorialClient { private final String host; private final int port; private final int count; public FactorialClient(String host, int port, int count) { this.host = host; this.port = port; this.count = count; } public void run() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new FactorialClientPipelineFactory(count)); // Make a new connection. ChannelFuture connectFuture = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection is made successfully. Channel channel = connectFuture.awaitUninterruptibly().getChannel(); // Get the handler instance to retrieve the answer. FactorialClientHandler handler = (FactorialClientHandler) channel.getPipeline().getLast(); // Print out the answer. System.err.format( "Factorial of %,d is: %,d", count, handler.getFactorial()); // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length != 3) { System.err.println( "Usage: " + FactorialClient.class.getSimpleName() + " "); return; } // Parse options. String host = args[0]; int port = Integer.parseInt(args[1]); int count = Integer.parseInt(args[2]); if (count <= 0) { throw new IllegalArgumentException("count must be a positive integer."); } new FactorialClient(host, port, count).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/FactorialClientHandler.java000066400000000000000000000101751225554127700334060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import java.math.BigInteger; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handler for a client-side channel. This handler maintains stateful * information which is specific to a certain channel using member variables. * Therefore, an instance of this handler can cover only one channel. You have * to create a new handler instance whenever you create a new channel and insert * this handler to avoid a race condition. */ public class FactorialClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( FactorialClientHandler.class.getName()); // Stateful properties private int i = 1; private int receivedMessages; private final int count; final BlockingQueue answer = new LinkedBlockingQueue(); public FactorialClientHandler(int count) { this.count = count; } public BigInteger getFactorial() { boolean interrupted = false; for (;;) { try { BigInteger factorial = answer.take(); if (interrupted) { Thread.currentThread().interrupt(); } return factorial; } catch (InterruptedException e) { interrupted = true; } } } @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { sendNumbers(e); } @Override public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) { sendNumbers(e); } @Override public void messageReceived( ChannelHandlerContext ctx, final MessageEvent e) { receivedMessages ++; if (receivedMessages == count) { // Offer the answer after closing the connection. e.getChannel().close().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { boolean offered = answer.offer((BigInteger) e.getMessage()); assert offered; } }); } } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } private void sendNumbers(ChannelStateEvent e) { Channel channel = e.getChannel(); while (channel.isWritable()) { if (i <= count) { channel.write(i); i ++; } else { break; } } } } FactorialClientPipelineFactory.java000066400000000000000000000036421225554127700350500ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.compression.ZlibDecoder; import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibWrapper; /** * Creates a newly configured {@link ChannelPipeline} for a client-side channel. */ public class FactorialClientPipelineFactory implements ChannelPipelineFactory { private final int count; public FactorialClientPipelineFactory(int count) { this.count = count; } public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); // Enable stream compression (you can remove these two if unnecessary) pipeline.addLast("deflater", new ZlibEncoder(ZlibWrapper.GZIP)); pipeline.addLast("inflater", new ZlibDecoder(ZlibWrapper.GZIP)); // Add the number codec first, pipeline.addLast("decoder", new BigIntegerDecoder()); pipeline.addLast("encoder", new NumberEncoder()); // and then business logic. pipeline.addLast("handler", new FactorialClientHandler(count)); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/FactorialServer.java000066400000000000000000000036021225554127700321350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * Receives a sequence of integers from a {@link FactorialClient} to calculate * the factorial of the specified integer. */ public class FactorialServer { private final int port; public FactorialServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new FactorialServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new FactorialServer(port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/FactorialServerHandler.java000066400000000000000000000061011225554127700334300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import java.math.BigInteger; import java.util.Formatter; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handler for a server-side channel. This handler maintains stateful * information which is specific to a certain channel using member variables. * Therefore, an instance of this handler can cover only one channel. You have * to create a new handler instance whenever you create a new channel and insert * this handler to avoid a race condition. */ public class FactorialServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( FactorialServerHandler.class.getName()); // Stateful properties. private int lastMultiplier = 1; private BigInteger factorial = new BigInteger(new byte[] { 1 }); @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Calculate the cumulative factorial and send it to the client. BigInteger number; if (e.getMessage() instanceof BigInteger) { number = (BigInteger) e.getMessage(); } else { number = new BigInteger(e.getMessage().toString()); } lastMultiplier = number.intValue(); factorial = factorial.multiply(number); e.getChannel().write(factorial); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { logger.info(new Formatter().format( "Factorial of %,d is: %,d", lastMultiplier, factorial).toString()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } FactorialServerPipelineFactory.java000066400000000000000000000036251225554127700351010ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.compression.ZlibDecoder; import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibWrapper; /** * Creates a newly configured {@link ChannelPipeline} for a server-side channel. */ public class FactorialServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); // Enable stream compression (you can remove these two if unnecessary) pipeline.addLast("deflater", new ZlibEncoder(ZlibWrapper.GZIP)); pipeline.addLast("inflater", new ZlibDecoder(ZlibWrapper.GZIP)); // Add the number codec first, pipeline.addLast("decoder", new BigIntegerDecoder()); pipeline.addLast("encoder", new NumberEncoder()); // and then business logic. // Please note we create a handler for every new channel // because it has stateful properties. pipeline.addLast("handler", new FactorialServerHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/factorial/NumberEncoder.java000066400000000000000000000041541225554127700315750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.factorial; import java.math.BigInteger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * Encodes a {@link Number} into the binary representation prepended with * a magic number ('F' or 0x46) and a 32-bit length prefix. For example, 42 * will be encoded to { 'F', 0, 0, 0, 1, 42 }. */ public class NumberEncoder extends OneToOneEncoder { @Override protected Object encode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof Number)) { // Ignore what this encoder can't encode. return msg; } // Convert to a BigInteger first for easier implementation. BigInteger v; if (msg instanceof BigInteger) { v = (BigInteger) msg; } else { v = new BigInteger(String.valueOf(msg)); } // Convert the number into a byte array. byte[] data = v.toByteArray(); int dataLength = data.length; // Construct a message. ChannelBuffer buf = ChannelBuffers.dynamicBuffer(); buf.writeByte((byte) 'F'); // magic number buf.writeInt(dataLength); // data length buf.writeBytes(data); // data // Return the constructed message. return buf; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/000077500000000000000000000000001225554127700252115ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/file/000077500000000000000000000000001225554127700261305ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/file/HttpStaticFileServer.java000066400000000000000000000034031225554127700330510ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.file; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class HttpStaticFileServer { private final int port; public HttpStaticFileServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new HttpStaticFileServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new HttpStaticFileServer(port).run(); } } HttpStaticFileServerHandler.java000066400000000000000000000272431225554127700343000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/file/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.file; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelFutureProgressListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.DefaultFileRegion; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.FileRegion; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedFile; import org.jboss.netty.util.CharsetUtil; import javax.activation.MimetypesFileTypeMap; import java.io.File; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import static org.jboss.netty.handler.codec.http.HttpMethod.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** * A simple handler that serves incoming HTTP requests to send their respective * HTTP responses. It also implements {@code 'If-Modified-Since'} header to * take advantage of browser cache, as described in * RFC 2616. * *

How Browser Caching Works

* * Web browser caching works with HTTP headers as illustrated by the following * sample: *
    *
  1. Request #1 returns the content of {@code /file1.txt}.
  2. *
  3. Contents of {@code /file1.txt} is cached by the browser.
  4. *
  5. Request #2 for {@code /file1.txt} does return the contents of the * file again. Rather, a 304 Not Modified is returned. This tells the * browser to use the contents stored in its cache.
  6. *
  7. The server knows the file has not been modified because the * {@code If-Modified-Since} date is the same as the file's last * modified date.
  8. *
* *
 * Request #1 Headers
 * ===================
 * GET /file1.txt HTTP/1.1
 *
 * Response #1 Headers
 * ===================
 * HTTP/1.1 200 OK
 * Date:               Tue, 01 Mar 2011 22:44:26 GMT
 * Last-Modified:      Wed, 30 Jun 2010 21:36:48 GMT
 * Expires:            Tue, 01 Mar 2012 22:44:26 GMT
 * Cache-Control:      private, max-age=31536000
 *
 * Request #2 Headers
 * ===================
 * GET /file1.txt HTTP/1.1
 * If-Modified-Since:  Wed, 30 Jun 2010 21:36:48 GMT
 *
 * Response #2 Headers
 * ===================
 * HTTP/1.1 304 Not Modified
 * Date:               Tue, 01 Mar 2011 22:44:28 GMT
 *
 * 
*/ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler { public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; public static final String HTTP_DATE_GMT_TIMEZONE = "GMT"; public static final int HTTP_CACHE_SECONDS = 60; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { HttpRequest request = (HttpRequest) e.getMessage(); if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String path = sanitizeUri(request.getUri()); if (path == null) { sendError(ctx, FORBIDDEN); return; } File file = new File(path); if (file.isHidden() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && ifModifiedSince.length() != 0) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client does // not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException fnfe) { sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); setContentLength(response, fileLength); setContentTypeHeader(response, file); setDateAndCacheHeaders(response, file); Channel ch = e.getChannel(); // Write the initial line and the header. ch.write(response); // Write the content. ChannelFuture writeFuture; if (ch.getPipeline().get(SslHandler.class) != null) { // Cannot use zero-copy with HTTPS. writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192)); } else { // No encryption - use zero-copy. final FileRegion region = new DefaultFileRegion(raf.getChannel(), 0, fileLength); writeFuture = ch.write(region); writeFuture.addListener(new ChannelFutureProgressListener() { public void operationComplete(ChannelFuture future) { region.releaseExternalResources(); } public void operationProgressed( ChannelFuture future, long amount, long current, long total) { System.out.printf("%s: %d / %d (+%d)%n", path, current, total, amount); } }); } // Decide whether to close the connection or not. if (!isKeepAlive(request)) { // Close the connection when the whole content is written out. writeFuture.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Channel ch = e.getChannel(); Throwable cause = e.getCause(); if (cause instanceof TooLongFrameException) { sendError(ctx, BAD_REQUEST); return; } cause.printStackTrace(); if (ch.isConnected()) { sendError(ctx, INTERNAL_SERVER_ERROR); } } private static String sanitizeUri(String uri) { // Decode the path. try { uri = URLDecoder.decode(uri, "UTF-8"); } catch (UnsupportedEncodingException e) { try { uri = URLDecoder.decode(uri, "ISO-8859-1"); } catch (UnsupportedEncodingException e1) { throw new Error(); } } // Convert file separators. uri = uri.replace('/', File.separatorChar); // Simplistic dumb security check. // You will have to do something serious in the production environment. if (uri.contains(File.separator + '.') || uri.contains('.' + File.separator) || uri.startsWith(".") || uri.endsWith(".")) { return null; } // Convert to absolute path. return System.getProperty("user.dir") + File.separator + uri; } private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); response.setContent(ChannelBuffers.copiedBuffer( "Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8)); // Close the connection as soon as the error message is sent. ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE); } /** * When file timestamp is the same as what the browser is sending up, send a "304 Not Modified" * * @param ctx * Context */ private static void sendNotModified(ChannelHandlerContext ctx) { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NOT_MODIFIED); setDateHeader(response); // Close the connection as soon as the error message is sent. ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE); } /** * Sets the Date header for the HTTP response * * @param response * HTTP response */ private static void setDateHeader(HttpResponse response) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE)); Calendar time = new GregorianCalendar(); response.headers().set(DATE, dateFormatter.format(time.getTime())); } /** * Sets the Date and Cache headers for the HTTP Response * * @param response * HTTP response * @param fileToCache * file to extract content type */ private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE)); // Date header Calendar time = new GregorianCalendar(); response.headers().set(DATE, dateFormatter.format(time.getTime())); // Add cache headers time.add(Calendar.SECOND, HTTP_CACHE_SECONDS); response.headers().set(EXPIRES, dateFormatter.format(time.getTime())); response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS); response.headers().set( LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified()))); } /** * Sets the content type header for the HTTP Response * * @param response * HTTP response * @param file * file to extract content type */ private static void setContentTypeHeader(HttpResponse response, File file) { MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath())); } } HttpStaticFileServerPipelineFactory.java000066400000000000000000000041661225554127700360170ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/file/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.file; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.stream.ChunkedWriteHandler; // Uncomment the following lines if you want HTTPS //import javax.net.ssl.SSLEngine; //import org.jboss.netty.example.securechat.SecureChatSslContextFactory; //import org.jboss.netty.handler.ssl.SslHandler; public class HttpStaticFileServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Uncomment the following lines if you want HTTPS //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); //engine.setUseClientMode(false); //pipeline.addLast("ssl", new SslHandler(engine)); pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); pipeline.addLast("handler", new HttpStaticFileServerHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/helloworld/000077500000000000000000000000001225554127700273645ustar00rootroot00000000000000HttpHelloWorldServer.java000066400000000000000000000040001225554127700342440ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/helloworld/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.helloworld; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import java.net.InetSocketAddress; import java.util.concurrent.Executors; /** * An HTTP server that sends back the content of the received HTTP request * in a pretty plaintext form. */ public class HttpHelloWorldServer { private final int port; public HttpHelloWorldServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Enable TCP_NODELAY to handle pipelined requests without latency. bootstrap.setOption("child.tcpNoDelay", true); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new HttpHelloWorldServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new HttpHelloWorldServer(port).run(); } } HttpHelloWorldServerHandler.java000066400000000000000000000060661225554127700355600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/helloworld/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.helloworld; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; public class HttpHelloWorldServerHandler extends SimpleChannelUpstreamHandler { private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); Channel ch = e.getChannel(); if (msg instanceof HttpRequest) { HttpRequest req = (HttpRequest) msg; if (is100ContinueExpected(req)) { Channels.write(ctx, Channels.future(ch), new DefaultHttpResponse(HTTP_1_1, CONTINUE)); } boolean keepAlive = isKeepAlive(req); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); response.setContent(ChannelBuffers.wrappedBuffer(CONTENT)); response.headers().set(CONTENT_TYPE, "text/plain"); response.headers().set(CONTENT_LENGTH, response.getContent().readableBytes()); if (!keepAlive) { ChannelFuture f = Channels.future(ch); f.addListener(ChannelFutureListener.CLOSE); Channels.write(ctx, f, response); } else { response.headers().set(CONNECTION, Values.KEEP_ALIVE); Channels.write(ctx, Channels.future(ch), response); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } } HttpHelloWorldServerPipelineFactory.java000066400000000000000000000040301225554127700372650ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/helloworld/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.helloworld; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import static org.jboss.netty.channel.Channels.*; public class HttpHelloWorldServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Uncomment the following line if you want HTTPS //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); //engine.setUseClientMode(false); //pipeline.addLast("ssl", new SslHandler(engine)); pipeline.addLast("decoder", new HttpRequestDecoder()); // Uncomment the following line if you don't want to handle HttpChunks. //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); pipeline.addLast("encoder", new HttpResponseEncoder()); // Remove the following line if you don't want automatic content compression. pipeline.addLast("deflater", new HttpContentCompressor()); pipeline.addLast("handler", new HttpHelloWorldServerHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/000077500000000000000000000000001225554127700263475ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/HttpSnoopClient.java000066400000000000000000000104571225554127700323160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.snoop; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.http.CookieEncoder; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpVersion; import java.net.InetSocketAddress; import java.net.URI; import java.util.concurrent.Executors; /** * A simple HTTP client that prints out the content of the HTTP response to * {@link System#out} to test {@link HttpSnoopServer}. */ public class HttpSnoopClient { private final URI uri; public HttpSnoopClient(URI uri) { this.uri = uri; } public void run() { String scheme = uri.getScheme() == null? "http" : uri.getScheme(); String host = uri.getHost() == null? "localhost" : uri.getHost(); int port = uri.getPort(); if (port == -1) { if ("http".equalsIgnoreCase(scheme)) { port = 80; } else if ("https".equalsIgnoreCase(scheme)) { port = 443; } } if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { System.err.println("Only HTTP(S) is supported."); return; } boolean ssl = "https".equalsIgnoreCase(scheme); // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new HttpSnoopClientPipelineFactory(ssl)); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. Channel channel = future.awaitUninterruptibly().getChannel(); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return; } // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath()); request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); // Set some example cookies. CookieEncoder httpCookieEncoder = new CookieEncoder(false); httpCookieEncoder.addCookie("my-cookie", "foo"); httpCookieEncoder.addCookie("another-cookie", "bar"); request.headers().set(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode()); // Send the HTTP request. channel.write(request); // Wait for the server to close the connection. channel.getCloseFuture().awaitUninterruptibly(); // Shut down executor threads to exit. bootstrap.releaseExternalResources(); } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println( "Usage: " + HttpSnoopClient.class.getSimpleName() + " "); return; } URI uri = new URI(args[0]); new HttpSnoopClient(uri).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/HttpSnoopClientHandler.java000066400000000000000000000053161225554127700336120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.snoop; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.util.CharsetUtil; public class HttpSnoopClientHandler extends SimpleChannelUpstreamHandler { private boolean readingChunks; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!readingChunks) { HttpResponse response = (HttpResponse) e.getMessage(); System.out.println("STATUS: " + response.getStatus()); System.out.println("VERSION: " + response.getProtocolVersion()); System.out.println(); if (!response.headers().names().isEmpty()) { for (String name: response.headers().names()) { for (String value: response.headers().getAll(name)) { System.out.println("HEADER: " + name + " = " + value); } } System.out.println(); } if (response.isChunked()) { readingChunks = true; System.out.println("CHUNKED CONTENT {"); } else { ChannelBuffer content = response.getContent(); if (content.readable()) { System.out.println("CONTENT {"); System.out.println(content.toString(CharsetUtil.UTF_8)); System.out.println("} END OF CONTENT"); } } } else { HttpChunk chunk = (HttpChunk) e.getMessage(); if (chunk.isLast()) { readingChunks = false; System.out.println("} END OF CHUNKED CONTENT"); } else { System.out.print(chunk.getContent().toString(CharsetUtil.UTF_8)); System.out.flush(); } } } } HttpSnoopClientPipelineFactory.java000066400000000000000000000042721225554127700352530ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.snoop; import static org.jboss.netty.channel.Channels.*; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.codec.http.HttpClientCodec; import org.jboss.netty.handler.codec.http.HttpContentDecompressor; import org.jboss.netty.handler.ssl.SslHandler; public class HttpSnoopClientPipelineFactory implements ChannelPipelineFactory { private final boolean ssl; public HttpSnoopClientPipelineFactory(boolean ssl) { this.ssl = ssl; } public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Enable HTTPS if necessary. if (ssl) { SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine(); engine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(engine)); } pipeline.addLast("codec", new HttpClientCodec()); // Remove the following line if you don't want automatic content decompression. pipeline.addLast("inflater", new HttpContentDecompressor()); // Uncomment the following line if you don't want to handle HttpChunks. //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); pipeline.addLast("handler", new HttpSnoopClientHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/HttpSnoopServer.java000066400000000000000000000037471225554127700323520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.snoop; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import java.net.InetSocketAddress; import java.util.concurrent.Executors; /** * An HTTP server that sends back the content of the received HTTP request * in a pretty plaintext form. */ public class HttpSnoopServer { private final int port; public HttpSnoopServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Enable TCP_NODELAY to handle pipelined requests without latency. bootstrap.setOption("child.tcpNoDelay", true); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new HttpSnoopServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new HttpSnoopServer(port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/HttpSnoopServerHandler.java000066400000000000000000000167511225554127700336470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.snoop; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.Cookie; import org.jboss.netty.handler.codec.http.CookieDecoder; import org.jboss.netty.handler.codec.http.CookieEncoder; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpChunkTrailer; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.QueryStringDecoder; import org.jboss.netty.util.CharsetUtil; public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler { private HttpRequest request; private boolean readingChunks; /** Buffer that stores the response content */ private final StringBuilder buf = new StringBuilder(); @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!readingChunks) { HttpRequest request = this.request = (HttpRequest) e.getMessage(); if (is100ContinueExpected(request)) { send100Continue(e); } buf.setLength(0); buf.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); buf.append("===================================\r\n"); buf.append("VERSION: " + request.getProtocolVersion() + "\r\n"); buf.append("HOSTNAME: " + getHost(request, "unknown") + "\r\n"); buf.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n"); for (Map.Entry h: request.headers()) { buf.append("HEADER: " + h.getKey() + " = " + h.getValue() + "\r\n"); } buf.append("\r\n"); QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri()); Map> params = queryStringDecoder.getParameters(); if (!params.isEmpty()) { for (Entry> p: params.entrySet()) { String key = p.getKey(); List vals = p.getValue(); for (String val : vals) { buf.append("PARAM: " + key + " = " + val + "\r\n"); } } buf.append("\r\n"); } if (request.isChunked()) { readingChunks = true; } else { ChannelBuffer content = request.getContent(); if (content.readable()) { buf.append("CONTENT: " + content.toString(CharsetUtil.UTF_8) + "\r\n"); } writeResponse(e); } } else { HttpChunk chunk = (HttpChunk) e.getMessage(); if (chunk.isLast()) { readingChunks = false; buf.append("END OF CONTENT\r\n"); HttpChunkTrailer trailer = (HttpChunkTrailer) chunk; if (!trailer.trailingHeaders().names().isEmpty()) { buf.append("\r\n"); for (String name: trailer.trailingHeaders().names()) { for (String value: trailer.trailingHeaders().getAll(name)) { buf.append("TRAILING HEADER: " + name + " = " + value + "\r\n"); } } buf.append("\r\n"); } writeResponse(e); } else { buf.append("CHUNK: " + chunk.getContent().toString(CharsetUtil.UTF_8) + "\r\n"); } } } private void writeResponse(MessageEvent e) { // Decide whether to close the connection or not. boolean keepAlive = isKeepAlive(request); // Build the response object. HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); response.setContent(ChannelBuffers.copiedBuffer(buf.toString(), CharsetUtil.UTF_8)); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); if (keepAlive) { // Add 'Content-Length' header only for a keep-alive connection. response.headers().set(CONTENT_LENGTH, response.getContent().readableBytes()); // Add keep alive header as per: // - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } // Encode the cookie. String cookieString = request.headers().get(COOKIE); if (cookieString != null) { CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); if (!cookies.isEmpty()) { // Reset the cookies if necessary. CookieEncoder cookieEncoder = new CookieEncoder(true); for (Cookie cookie : cookies) { cookieEncoder.addCookie(cookie); response.headers().add(SET_COOKIE, cookieEncoder.encode()); } } } else { // Browser sent no cookie. Add some. CookieEncoder cookieEncoder = new CookieEncoder(true); cookieEncoder.addCookie("key1", "value1"); response.headers().add(SET_COOKIE, cookieEncoder.encode()); cookieEncoder.addCookie("key2", "value2"); response.headers().add(SET_COOKIE, cookieEncoder.encode()); } // Write the response. ChannelFuture future = e.getChannel().write(response); // Close the non-keep-alive connection after the write operation is done. if (!keepAlive) { future.addListener(ChannelFutureListener.CLOSE); } } private static void send100Continue(MessageEvent e) { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE); e.getChannel().write(response); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } } HttpSnoopServerPipelineFactory.java000066400000000000000000000040111225554127700352720ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/snoop/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.snoop; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; public class HttpSnoopServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Uncomment the following line if you want HTTPS //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); //engine.setUseClientMode(false); //pipeline.addLast("ssl", new SslHandler(engine)); pipeline.addLast("decoder", new HttpRequestDecoder()); // Uncomment the following line if you don't want to handle HttpChunks. //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); pipeline.addLast("encoder", new HttpResponseEncoder()); // Remove the following line if you don't want automatic content compression. pipeline.addLast("deflater", new HttpContentCompressor()); pipeline.addLast("handler", new HttpSnoopServerHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/tunnel/000077500000000000000000000000001225554127700265165ustar00rootroot00000000000000HttpTunnelingClientExample.java000066400000000000000000000115431225554127700345640ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/tunnel/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.tunnel; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.http.HttpTunnelingClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.logging.LoggingHandler; import org.jboss.netty.logging.InternalLogLevel; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.URI; import java.util.concurrent.Executors; /** * An HTTP tunneled version of the telnet client example. Please refer to the * API documentation of the org.jboss.netty.channel.socket.http package * for the detailed instruction on how to deploy the server-side HTTP tunnel in * your Servlet container. */ public class HttpTunnelingClientExample { private final URI uri; public HttpTunnelingClientExample(URI uri) { this.uri = uri; } public void run() throws IOException { String scheme = uri.getScheme() == null? "http" : uri.getScheme(); // Configure the client. ClientBootstrap b = new ClientBootstrap( new HttpTunnelingClientSocketChannelFactory( new OioClientSocketChannelFactory(Executors.newCachedThreadPool()))); b.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringDecoder(), new StringEncoder(), new LoggingHandler(InternalLogLevel.INFO)); } }); // Set additional options required by the HTTP tunneling transport. b.setOption("serverName", uri.getHost()); b.setOption("serverPath", uri.getRawPath()); // Configure SSL if necessary if ("https".equals(scheme)) { b.setOption("sslContext", SecureChatSslContextFactory.getClientContext()); } else if (!"http".equals(scheme)) { // Only HTTP and HTTPS are supported. System.err.println("Only HTTP(S) is supported."); return; } // Make the connection attempt. ChannelFuture channelFuture = b.connect( new InetSocketAddress(uri.getHost(), uri.getPort())); channelFuture.awaitUninterruptibly(); // Read commands from the stdin. System.out.println("Enter text ('quit' to exit)"); ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (; ;) { String line = in.readLine(); if (line == null || "quit".equalsIgnoreCase(line)) { break; } // Sends the received line to the server. lastWriteFuture = channelFuture.getChannel().write(line); } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.awaitUninterruptibly(); } channelFuture.getChannel().close(); // Wait until the connection is closed or the connection attempt fails. channelFuture.getChannel().getCloseFuture().awaitUninterruptibly(); // Shut down all threads. b.releaseExternalResources(); } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println( "Usage: " + HttpTunnelingClientExample.class.getSimpleName() + " "); System.err.println( "Example: " + HttpTunnelingClientExample.class.getSimpleName() + " http://localhost:8080/netty-tunnel"); return; } URI uri = new URI(args[0]); new HttpTunnelingClientExample(uri).run(); } } LocalEchoServerRegistration.java000066400000000000000000000035711225554127700347230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/tunnel/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.tunnel; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.local.DefaultLocalServerChannelFactory; import org.jboss.netty.channel.local.LocalAddress; import org.jboss.netty.example.echo.EchoServerHandler; /** * Deploy this in JBossAS 5 or other IoC container by adding the following bean. * *
 * <bean name="org.jboss.netty.example.http.tunnel.LocalEchoServerRegistration"
 *       class="org.jboss.netty.example.http.tunnel.LocalEchoServerRegistration" />
 * 
*/ public class LocalEchoServerRegistration { private final ChannelFactory factory = new DefaultLocalServerChannelFactory(); private volatile Channel serverChannel; public void start() { ServerBootstrap serverBootstrap = new ServerBootstrap(factory); EchoServerHandler handler = new EchoServerHandler(); serverBootstrap.getPipeline().addLast("handler", handler); // Note that "myLocalServer" is the endpoint which was specified in web.xml. serverChannel = serverBootstrap.bind(new LocalAddress("myLocalServer")); } public void stop() { serverChannel.close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/000077500000000000000000000000001225554127700264755ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/HttpUploadClient.java000066400000000000000000002261431225554127700325730ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.upload; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.http.CookieEncoder; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.handler.codec.http.QueryStringEncoder; import org.jboss.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import org.jboss.netty.handler.codec.http.multipart.DiskAttribute; import org.jboss.netty.handler.codec.http.multipart.DiskFileUpload; import org.jboss.netty.handler.codec.http.multipart.HttpDataFactory; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestEncoder; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestEncoder.ErrorDataEncoderException; import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.io.File; import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.Executors; public class HttpUploadClient { private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadClient.class); private final String baseUri; private final String filePath; public HttpUploadClient(String baseUri, String filePath) { this.baseUri = baseUri; this.filePath = filePath; } public void run() { String postSimple, postFile, get; if (baseUri.endsWith("/")) { postSimple = baseUri + "formpost"; postFile = baseUri + "formpostmultipart"; get = baseUri + "formget"; } else { postSimple = baseUri + "/formpost"; postFile = baseUri + "/formpostmultipart"; get = baseUri + "/formget"; } URI uriSimple; try { uriSimple = new URI(postSimple); } catch (URISyntaxException e) { logger.error("Invalid URI syntax" + e.getCause()); return; } String scheme = uriSimple.getScheme() == null? "http" : uriSimple.getScheme(); String host = uriSimple.getHost() == null? "localhost" : uriSimple.getHost(); int port = uriSimple.getPort(); if (port == -1) { if ("http".equalsIgnoreCase(scheme)) { port = 80; } else if ("https".equalsIgnoreCase(scheme)) { port = 443; } } if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { logger.error("Only HTTP(S) is supported."); return; } boolean ssl = "https".equalsIgnoreCase(scheme); URI uriFile; try { uriFile = new URI(postFile); } catch (URISyntaxException e) { logger.error("Error: " + e.getMessage()); return; } File file = new File(filePath); if (! file.canRead()) { logger.error("A correct path is needed"); return; } // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new HttpUploadClientPipelineFactory(ssl)); // setup the factory: here using a mixed memory/disk based on size threshold HttpDataFactory factory = new DefaultHttpDataFactory( DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) DiskFileUpload.baseDirectory = null; // system temp directory DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) DiskAttribute.baseDirectory = null; // system temp directory // Simple Get form: no factory used (not usable) List> headers = formget(bootstrap, host, port, get, uriSimple); if (headers == null) { factory.cleanAllHttpDatas(); return; } // Simple Post form: factory used for big attributes List bodylist = formpost(bootstrap, host, port, uriSimple, file, factory, headers); if (bodylist == null) { factory.cleanAllHttpDatas(); return; } // Multipart Post form: factory used formpostmultipart(bootstrap, host, port, uriFile, factory, headers, bodylist); // Shut down executor threads to exit. bootstrap.releaseExternalResources(); // Really clean all temporary files if they still exist factory.cleanAllHttpDatas(); } /** * Standard usage of HTTP API in Netty without file Upload (get is not able to achieve File upload * due to limitation on request size). * @return the list of headers that will be used in every example after **/ private static List> formget(ClientBootstrap bootstrap, String host, int port, String get, URI uriSimple) { // XXX /formget // No use of HttpPostRequestEncoder since not a POST // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. Channel channel = future.awaitUninterruptibly().getChannel(); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return null; } // Prepare the HTTP request. QueryStringEncoder encoder = new QueryStringEncoder(get); // add Form attribute encoder.addParam("getform", "GET"); encoder.addParam("info", "first value"); encoder.addParam("secondinfo", "secondvalue ���&"); // not the big one since it is not compatible with GET size // encoder.addParam("thirdinfo", textArea); encoder.addParam("thirdinfo", "third value\r\ntest second line\r\n\r\nnew line\r\n"); encoder.addParam("Send", "Send"); URI uriGet; try { uriGet = new URI(encoder.toString()); } catch (URISyntaxException e) { logger.error("Error: " + e.getMessage()); bootstrap.releaseExternalResources(); return null; } HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString()); request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ',' + HttpHeaders.Values.DEFLATE); request.headers().set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); request.headers().set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr"); request.headers().set(HttpHeaders.Names.REFERER, uriSimple.toString()); request.headers().set(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side"); request.headers().set(HttpHeaders.Names.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); //connection will not close but needed // request.headers().set("Connection","keep-alive"); // request.headers().set("Keep-Alive","300"); CookieEncoder httpCookieEncoder = new CookieEncoder(false); httpCookieEncoder.addCookie("my-cookie", "foo"); httpCookieEncoder.addCookie("another-cookie", "bar"); request.headers().set(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode()); List> headers = request.headers().entries(); // send request channel.write(request); // Wait for the server to close the connection. channel.getCloseFuture().awaitUninterruptibly(); return headers; } /** * Standard post without multipart but already support on Factory (memory management) * * @return the list of HttpData object (attribute and file) to be reused on next post */ private static List formpost(ClientBootstrap bootstrap, String host, int port, URI uriSimple, File file, HttpDataFactory factory, List> headers) { // XXX /formpost // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. Channel channel = future.awaitUninterruptibly().getChannel(); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return null; } // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString()); // Use the PostBody encoder HttpPostRequestEncoder bodyRequestEncoder = null; try { bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false); // false => not multipart } catch (NullPointerException e) { // should not be since args are not null e.printStackTrace(); } catch (ErrorDataEncoderException e) { // test if method is a POST method e.printStackTrace(); } // it is legal to add directly header or cookie into the request until finalize for (Entry entry : headers) { request.headers().set(entry.getKey(), entry.getValue()); } // add Form attribute try { bodyRequestEncoder.addBodyAttribute("getform", "POST"); bodyRequestEncoder.addBodyAttribute("info", "first value"); bodyRequestEncoder.addBodyAttribute("secondinfo", "secondvalue ���&"); bodyRequestEncoder.addBodyAttribute("thirdinfo", textArea); bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false); bodyRequestEncoder.addBodyAttribute("Send", "Send"); } catch (NullPointerException e) { // should not be since not null args e.printStackTrace(); } catch (ErrorDataEncoderException e) { // if an encoding error occurs e.printStackTrace(); } // finalize request try { request = bodyRequestEncoder.finalizeRequest(); } catch (ErrorDataEncoderException e) { // if an encoding error occurs e.printStackTrace(); } // Create the bodylist to be reused on the last version with Multipart support List bodylist = bodyRequestEncoder.getBodyListAttributes(); // send request channel.write(request); // test if request was chunked and if so, finish the write if (bodyRequestEncoder.isChunked()) { // could do either request.isChunked() // either do it through ChunkedWriteHandler channel.write(bodyRequestEncoder).awaitUninterruptibly(); } // Do not clear here since we will reuse the InterfaceHttpData on the next request // for the example (limit action on client side). Take this as a broadcast of the same // request on both Post actions. // // On standard program, it is clearly recommended to clean all files after each request // bodyRequestEncoder.cleanFiles(); // Wait for the server to close the connection. channel.getCloseFuture().awaitUninterruptibly(); return bodylist; } /** * Multipart example */ private static void formpostmultipart(ClientBootstrap bootstrap, String host, int port, URI uriFile, HttpDataFactory factory, List> headers, List bodylist) { // XXX /formpostmultipart // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. Channel channel = future.awaitUninterruptibly().getChannel(); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return; } // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString()); // Use the PostBody encoder HttpPostRequestEncoder bodyRequestEncoder = null; try { bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, true); // true => multipart } catch (NullPointerException e) { // should not be since no null args e.printStackTrace(); } catch (ErrorDataEncoderException e) { // test if method is a POST method e.printStackTrace(); } // it is legal to add directly header or cookie into the request until finalize for (Entry entry : headers) { request.headers().set(entry.getKey(), entry.getValue()); } // add Form attribute from previous request in formpost() try { bodyRequestEncoder.setBodyHttpDatas(bodylist); } catch (NullPointerException e1) { // should not be since previously created e1.printStackTrace(); } catch (ErrorDataEncoderException e1) { // again should not be since previously encoded (except if an error occurs previously) e1.printStackTrace(); } // finalize request try { bodyRequestEncoder.finalizeRequest(); } catch (ErrorDataEncoderException e) { // if an encoding error occurs e.printStackTrace(); } // send request channel.write(request); // test if request was chunked and if so, finish the write if (bodyRequestEncoder.isChunked()) { channel.write(bodyRequestEncoder).awaitUninterruptibly(); } // Now no more use of file representation (and list of HttpData) bodyRequestEncoder.cleanFiles(); // Wait for the server to close the connection. channel.getCloseFuture().awaitUninterruptibly(); } public static void main(String[] args) { if (args.length != 2) { logger.error( "Usage: " + HttpUploadClient.class.getSimpleName() + " baseURI filePath"); return; } String baseUri = args[0]; String filePath = args[1]; new HttpUploadClient(baseUri, filePath).run(); } // use to simulate a small TEXTAREA field in a form private static final String textArea = "short text"; // use to simulate a big TEXTAREA field in a form private static final String textAreaLong = "lkjlkjlKJLKJLKJLKJLJlkj lklkj\r\n\r\nLKJJJJJJJJKKKKKKKKKKKKKKK ����&\r\n\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"; } HttpUploadClientHandler.java000066400000000000000000000060511225554127700340040ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.upload; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; public class HttpUploadClientHandler extends SimpleChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadClientHandler.class); private boolean readingChunks; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!readingChunks) { HttpResponse response = (HttpResponse) e.getMessage(); logger.info("STATUS: " + response.getStatus()); logger.info("VERSION: " + response.getProtocolVersion()); if (!response.headers().names().isEmpty()) { for (String name: response.headers().names()) { for (String value: response.headers().getAll(name)) { logger.info("HEADER: " + name + " = " + value); } } } if (response.getStatus().getCode() == 200 && response.isChunked()) { readingChunks = true; logger.info("CHUNKED CONTENT {"); } else { ChannelBuffer content = response.getContent(); if (content.readable()) { logger.info("CONTENT {"); logger.info(content.toString(CharsetUtil.UTF_8)); logger.info("} END OF CONTENT"); } } } else { HttpChunk chunk = (HttpChunk) e.getMessage(); if (chunk.isLast()) { readingChunks = false; logger.info("} END OF CHUNKED CONTENT"); } else { logger.info(chunk.getContent().toString(CharsetUtil.UTF_8)); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } } HttpUploadClientPipelineFactory.java000066400000000000000000000044501225554127700355250ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.upload; import static org.jboss.netty.channel.Channels.*; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.codec.http.HttpClientCodec; import org.jboss.netty.handler.codec.http.HttpContentDecompressor; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedWriteHandler; public class HttpUploadClientPipelineFactory implements ChannelPipelineFactory { private final boolean ssl; public HttpUploadClientPipelineFactory(boolean ssl) { this.ssl = ssl; } public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Enable HTTPS if necessary. if (ssl) { SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine(); engine.setUseClientMode(true); SslHandler handler = new SslHandler(engine); handler.setIssueHandshake(true); pipeline.addLast("ssl", handler); } pipeline.addLast("codec", new HttpClientCodec()); // Remove the following line if you don't want automatic content decompression. pipeline.addLast("inflater", new HttpContentDecompressor()); // to be used since huge file transfer pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); pipeline.addLast("handler", new HttpUploadClientHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/HttpUploadServer.java000066400000000000000000000035311225554127700326150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.upload; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class HttpUploadServer { private final int port; public static boolean isSSL; public HttpUploadServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new HttpUploadServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } if (args.length > 1) { isSSL = true; } new HttpUploadServer(port).run(); } } HttpUploadServerHandler.java000066400000000000000000000523311225554127700340360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.upload; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.Cookie; import org.jboss.netty.handler.codec.http.CookieDecoder; import org.jboss.netty.handler.codec.http.CookieEncoder; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.handler.codec.http.QueryStringDecoder; import org.jboss.netty.handler.codec.http.multipart.Attribute; import org.jboss.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import org.jboss.netty.handler.codec.http.multipart.DiskAttribute; import org.jboss.netty.handler.codec.http.multipart.DiskFileUpload; import org.jboss.netty.handler.codec.http.multipart.FileUpload; import org.jboss.netty.handler.codec.http.multipart.HttpDataFactory; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.IncompatibleDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData; import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import java.io.IOException; import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadServerHandler.class); private HttpRequest request; private boolean readingChunks; private final StringBuilder responseContent = new StringBuilder(); private static final HttpDataFactory factory = new DefaultHttpDataFactory( DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE private HttpPostRequestDecoder decoder; static { //To limit to roughly 5MB each attribute, including fileupload //factory.setMaxLimit(5000000); DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file // on exit (in normal // exit) DiskFileUpload.baseDirectory = null; // system temp directory DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on // exit (in normal exit) DiskAttribute.baseDirectory = null; // system temp directory } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (decoder != null) { decoder.cleanFiles(); } } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!readingChunks) { // clean previous FileUpload if Any if (decoder != null) { decoder.cleanFiles(); decoder = null; } HttpRequest request = this.request = (HttpRequest) e.getMessage(); URI uri = new URI(request.getUri()); if (!uri.getPath().startsWith("/form")) { // Write Menu writeMenu(e); return; } responseContent.setLength(0); responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); responseContent.append("===================================\r\n"); responseContent.append("VERSION: " + request.getProtocolVersion().getText() + "\r\n"); responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n"); responseContent.append("\r\n\r\n"); // new method for (Entry entry: request.headers()) { responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n"); } responseContent.append("\r\n\r\n"); // new method Set cookies; String value = request.headers().get(HttpHeaders.Names.COOKIE); if (value == null) { cookies = Collections.emptySet(); } else { CookieDecoder decoder = new CookieDecoder(); cookies = decoder.decode(value); } for (Cookie cookie: cookies) { responseContent.append("COOKIE: " + cookie.toString() + "\r\n"); } responseContent.append("\r\n\r\n"); QueryStringDecoder decoderQuery = new QueryStringDecoder(request .getUri()); Map> uriAttributes = decoderQuery .getParameters(); for (Entry> attr: uriAttributes.entrySet()) { for (String attrVal: attr.getValue()) { responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n"); } } responseContent.append("\r\n\r\n"); // if GET Method: should not try to create a HttpPostRequestDecoder try { decoder = new HttpPostRequestDecoder(factory, request); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); responseContent.append(e1.getMessage()); writeResponse(e.getChannel()); Channels.close(e.getChannel()); return; } catch (IncompatibleDataDecoderException e1) { // GET Method: should not try to create a HttpPostRequestDecoder // So OK but stop here responseContent.append(e1.getMessage()); responseContent.append("\r\n\r\nEND OF GET CONTENT\r\n"); writeResponse(e.getChannel()); return; } responseContent.append("Is Chunked: " + request.isChunked() + "\r\n"); responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n"); if (request.isChunked()) { // Chunk version responseContent.append("Chunks: "); readingChunks = true; } else { // Not chunk version readHttpDataAllReceive(e.getChannel()); responseContent .append("\r\n\r\nEND OF NOT CHUNKED CONTENT\r\n"); writeResponse(e.getChannel()); } } else { // New chunk is received HttpChunk chunk = (HttpChunk) e.getMessage(); try { decoder.offer(chunk); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); responseContent.append(e1.getMessage()); writeResponse(e.getChannel()); Channels.close(e.getChannel()); return; } responseContent.append('o'); // example of reading chunk by chunk (minimize memory usage due to Factory) readHttpDataChunkByChunk(); // example of reading only if at the end if (chunk.isLast()) { readHttpDataAllReceive(e.getChannel()); writeResponse(e.getChannel()); readingChunks = false; } } } /** * Example of reading all InterfaceHttpData from finished transfer */ private void readHttpDataAllReceive(Channel channel) { List datas; try { datas = decoder.getBodyHttpDatas(); } catch (NotEnoughDataDecoderException e1) { // Should not be! e1.printStackTrace(); responseContent.append(e1.getMessage()); writeResponse(channel); Channels.close(channel); return; } for (InterfaceHttpData data: datas) { writeHttpData(data); } responseContent.append("\r\n\r\nEND OF CONTENT AT FINAL END\r\n"); } /** * Example of reading request by chunk and getting values from chunk to * chunk */ private void readHttpDataChunkByChunk() { try { while (decoder.hasNext()) { InterfaceHttpData data = decoder.next(); if (data != null) { // new value writeHttpData(data); } } } catch (EndOfDataDecoderException e1) { // end responseContent .append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n"); } } private void writeHttpData(InterfaceHttpData data) { if (data.getHttpDataType() == HttpDataType.Attribute) { Attribute attribute = (Attribute) data; String value; try { value = attribute.getValue(); } catch (IOException e1) { // Error while reading data from File, only print name and error e1.printStackTrace(); responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": " + attribute.getName() + " Error while reading value: " + e1.getMessage() + "\r\n"); return; } if (value.length() > 100) { responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": " + attribute.getName() + " data too long\r\n"); } else { responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": " + attribute.toString() + "\r\n"); } } else { responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data.toString() + "\r\n"); if (data.getHttpDataType() == HttpDataType.FileUpload) { FileUpload fileUpload = (FileUpload) data; if (fileUpload.isCompleted()) { if (fileUpload.length() < 10000) { responseContent.append("\tContent of file\r\n"); try { responseContent.append(fileUpload.getString(fileUpload.getCharset())); } catch (IOException e1) { // do nothing for the example e1.printStackTrace(); } responseContent.append("\r\n"); } else { responseContent .append("\tFile too long to be printed out:" + fileUpload.length() + "\r\n"); } // fileUpload.isInMemory();// tells if the file is in Memory // or on File // fileUpload.renameTo(dest); // enable to move into another // File dest // decoder.removeFileUploadFromClean(fileUpload); //remove // the File of to delete file } else { responseContent .append("\tFile to be continued but should not!\r\n"); } } } } private void writeResponse(Channel channel) { // Convert the response content to a ChannelBuffer. ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent .toString(), CharsetUtil.UTF_8); responseContent.setLength(0); // Decide whether to close the connection or not. boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request .headers().get(HttpHeaders.Names.CONNECTION)) || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request .headers().get(HttpHeaders.Names.CONNECTION)); // Build the response object. HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); response.setContent(buf); response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); if (!close) { // There's no need to add 'Content-Length' header // if this is the last response. response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String .valueOf(buf.readableBytes())); } Set cookies; String value = request.headers().get(HttpHeaders.Names.COOKIE); if (value == null) { cookies = Collections.emptySet(); } else { CookieDecoder decoder = new CookieDecoder(); cookies = decoder.decode(value); } if (!cookies.isEmpty()) { // Reset the cookies if necessary. CookieEncoder cookieEncoder = new CookieEncoder(true); for (Cookie cookie: cookies) { cookieEncoder.addCookie(cookie); response.headers().add(HttpHeaders.Names.SET_COOKIE, cookieEncoder .encode()); cookieEncoder = new CookieEncoder(true); } } // Write the response. ChannelFuture future = channel.write(response); // Close the connection after the write operation is done if necessary. if (close) { future.addListener(ChannelFutureListener.CLOSE); } } private void writeMenu(MessageEvent e) { // print several HTML forms // Convert the response content to a ChannelBuffer. responseContent.setLength(0); // create Pseudo Menu responseContent.append(""); responseContent.append(""); responseContent.append("Netty Test Form\r\n"); responseContent.append("\r\n"); responseContent .append(""); responseContent.append(""); responseContent.append(""); responseContent.append(""); responseContent.append(""); responseContent.append("
"); responseContent.append("

Netty Test Form

"); responseContent.append("Choose one FORM"); responseContent.append("
\r\n"); // GET responseContent .append("
GET FORM
"); responseContent.append("
"); responseContent .append(""); responseContent.append(""); responseContent .append(""); responseContent .append(""); responseContent .append(""); responseContent .append(""); responseContent.append("
Fill with value:
Fill with value:
"); responseContent .append("
Fill with value:
"); responseContent.append("
\r\n"); responseContent .append("

"); // POST responseContent .append("
POST FORM
"); responseContent.append("
"); responseContent .append(""); responseContent.append(""); responseContent .append(""); responseContent .append(""); responseContent .append(""); responseContent .append(""); responseContent.append("
Fill with value:
Fill with value:
"); responseContent .append("
Fill with value:
"); responseContent .append("
Fill with file (only file name will be transmitted):
" + ""); responseContent.append("
\r\n"); responseContent .append("

"); // POST with enctype="multipart/form-data" responseContent .append("
POST MULTIPART FORM
"); responseContent .append("
"); responseContent .append(""); responseContent.append(""); responseContent .append(""); responseContent .append(""); responseContent .append(""); responseContent .append(""); responseContent.append("
Fill with value:
Fill with value:
"); responseContent .append("
Fill with value:
"); responseContent .append("
Fill with file:
"); responseContent.append("
\r\n"); responseContent .append("

"); responseContent.append(""); responseContent.append(""); ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent .toString(), CharsetUtil.UTF_8); // Build the response object. HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); response.setContent(buf); response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8"); response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf .readableBytes())); // Write the response. e.getChannel().write(response); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { logger.error(responseContent.toString(), e.getCause()); e.getChannel().close(); } } HttpUploadServerPipelineFactory.java000066400000000000000000000041611225554127700355540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/upload/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.upload; import static org.jboss.netty.channel.Channels.*; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.ssl.SslHandler; public class HttpUploadServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); if (HttpUploadServer.isSSL) { SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); engine.setUseClientMode(false); SslHandler handler = new SslHandler(engine); handler.setIssueHandshake(true); pipeline.addLast("ssl", handler); } pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("encoder", new HttpResponseEncoder()); // Remove the following line if you don't want automatic content compression. pipeline.addLast("deflater", new HttpContentCompressor()); pipeline.addLast("handler", new HttpUploadServerHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/000077500000000000000000000000001225554127700273675ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/autobahn/000077500000000000000000000000001225554127700311705ustar00rootroot00000000000000AutobahnServer.java000066400000000000000000000037251225554127700347130ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/autobahn/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.autobahn; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * A Web Socket echo server for running the autobahn test * suite */ public class AutobahnServer { private final int port; public AutobahnServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // bootstrap.setOption("child.tcpNoDelay", true); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new AutobahnServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); System.out.println("Web Socket Server started at port " + port); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 9000; } new AutobahnServer(port).run(); } } AutobahnServerHandler.java000066400000000000000000000143551225554127700362120ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/autobahn/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.autobahn; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import static org.jboss.netty.handler.codec.http.HttpMethod.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; /** * Handles handshakes and messages */ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(AutobahnServerHandler.class); private WebSocketServerHandshaker handshaker; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpRequest) { handleHttpRequest(ctx, (HttpRequest) msg); } else if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); } } private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( getWebSocketLocation(req), null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); } else { handshaker.handshake(ctx.getChannel(), req).addListener(WebSocketServerHandshaker.HANDSHAKE_LISTENER); } } private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { if (logger.isDebugEnabled()) { logger.debug(String .format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName())); } if (frame instanceof CloseWebSocketFrame) { handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); } else if (frame instanceof PingWebSocketFrame) { ctx.getChannel().write( new PongWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); } else if (frame instanceof TextWebSocketFrame) { // String text = ((TextWebSocketFrame) frame).getText(); ctx.getChannel().write( new TextWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); } else if (frame instanceof BinaryWebSocketFrame) { ctx.getChannel().write( new BinaryWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); } else if (frame instanceof ContinuationWebSocketFrame) { ctx.getChannel().write( new ContinuationWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); } else if (frame instanceof PongWebSocketFrame) { // Ignore } else { throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() .getName())); } } private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { // Generate an error page if response status code is not OK (200). if (res.getStatus().getCode() != 200) { res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); setContentLength(res, res.getContent().readableBytes()); } // Send the response and close the connection if necessary. ChannelFuture f = ctx.getChannel().write(res); if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } private static String getWebSocketLocation(HttpRequest req) { return "ws://" + req.headers().get(HttpHeaders.Names.HOST); } } AutobahnServerPipelineFactory.java000066400000000000000000000030561225554127700377260ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/autobahn/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.autobahn; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; /** */ public class AutobahnServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("handler", new AutobahnServerHandler()); return pipeline; } } package-info.java000066400000000000000000000046141225554127700343050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/autobahn/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * This package is intended for use with testing against the Python * AutoBahn test suite. * * Autobahn installation documentation can be found here. * *

How to run the tests on Ubuntu.

* *

01. Install python (if not already installed). * *

02. Install Python Setup Tools if not already * installed. sudo apt-get install python-setuptools * *

03. Add ppa:twisted-dev/ppa to your system's Software Sources * *

04. Install Twisted: sudo apt-get install python-twisted * *

05. Install AutoBahn: sudo easy_install autobahntestsuite. Test using wstest --help. * *

06. Create a directory for test configuration and results: mkdir autobahn cd autobahn. * *

07. Create fuzzing_clinet_spec.json in the above directory * {@code * { * "options": {"failByDrop": false}, * "outdir": "./reports/servers", * * "servers": [ * {"agent": "Netty", * "url": "ws://localhost:9000", * "options": {"version": 18}} * ], * * "cases": ["*"], * "exclude-cases": [], * "exclude-agent-cases": {} * } * } * *

08. Run the AutobahnServer located in this package. If you are in Eclipse IDE, right click on * AutobahnServer.java and select Run As > Java Application. * *

09. Run the Autobahn test wstest -m fuzzingclient -s fuzzingclient.json. * *

10. See the results in ./reports/servers/index.html */ package org.jboss.netty.example.http.websocketx.autobahn; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/client/000077500000000000000000000000001225554127700306455ustar00rootroot00000000000000WebSocketClient.java000066400000000000000000000142511225554127700344610ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/client/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ //The MIT License // //Copyright (c) 2009 Carl Bystršm // //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: // //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. package org.jboss.netty.example.http.websocketx.client; import java.net.InetSocketAddress; import java.net.URI; import java.util.HashMap; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.http.HttpRequestEncoder; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; import org.jboss.netty.handler.codec.http.websocketx.WebSocketVersion; public class WebSocketClient { private final URI uri; public WebSocketClient(URI uri) { this.uri = uri; } public void run() throws Exception { ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); Channel ch = null; try { String protocol = uri.getScheme(); if (!"ws".equals(protocol)) { throw new IllegalArgumentException("Unsupported protocol: " + protocol); } HashMap customHeaders = new HashMap(); customHeaders.put("MyHeader", "MyValue"); // Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00. // If you change it to V00, ping is not supported and remember to change // HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline. final WebSocketClientHandshaker handshaker = new WebSocketClientHandshakerFactory().newHandshaker( uri, WebSocketVersion.V13, null, false, customHeaders); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder", new HttpResponseDecoder()); pipeline.addLast("encoder", new HttpRequestEncoder()); pipeline.addLast("ws-handler", new WebSocketClientHandler(handshaker)); return pipeline; } }); // Connect System.out.println("WebSocket Client connecting"); ChannelFuture future = bootstrap.connect( new InetSocketAddress(uri.getHost(), uri.getPort())); future.syncUninterruptibly(); ch = future.getChannel(); handshaker.handshake(ch).syncUninterruptibly(); // Send 10 messages and wait for responses System.out.println("WebSocket Client sending message"); for (int i = 0; i < 1000; i++) { ch.write(new TextWebSocketFrame("Message #" + i)); } // Ping System.out.println("WebSocket Client sending ping"); ch.write(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6}))); // Close System.out.println("WebSocket Client sending close"); ch.write(new CloseWebSocketFrame()); // WebSocketClientHandler will close the connection when the server // responds to the CloseWebSocketFrame. ch.getCloseFuture().awaitUninterruptibly(); } finally { if (ch != null) { ch.close(); } bootstrap.releaseExternalResources(); } } public static void main(String[] args) throws Exception { URI uri; if (args.length > 0) { uri = new URI(args[0]); } else { uri = new URI("ws://localhost:8080/websocket"); } new WebSocketClient(uri).run(); } } WebSocketClientHandler.java000066400000000000000000000112361225554127700357570ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/client/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ //The MIT License // //Copyright (c) 2009 Carl Bystršm // //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: // //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. package org.jboss.netty.example.http.websocketx.client; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; import org.jboss.netty.util.CharsetUtil; public class WebSocketClientHandler extends SimpleChannelUpstreamHandler { private final WebSocketClientHandshaker handshaker; public WebSocketClientHandler(WebSocketClientHandshaker handshaker) { this.handshaker = handshaker; } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("WebSocket Client disconnected!"); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Channel ch = ctx.getChannel(); if (!handshaker.isHandshakeComplete()) { handshaker.finishHandshake(ch, (HttpResponse) e.getMessage()); System.out.println("WebSocket Client connected!"); return; } if (e.getMessage() instanceof HttpResponse) { HttpResponse response = (HttpResponse) e.getMessage(); throw new Exception("Unexpected HttpResponse (status=" + response.getStatus() + ", content=" + response.getContent().toString(CharsetUtil.UTF_8) + ')'); } WebSocketFrame frame = (WebSocketFrame) e.getMessage(); if (frame instanceof TextWebSocketFrame) { TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; System.out.println("WebSocket Client received message: " + textFrame.getText()); } else if (frame instanceof PongWebSocketFrame) { System.out.println("WebSocket Client received pong"); } else if (frame instanceof CloseWebSocketFrame) { System.out.println("WebSocket Client received closing"); ch.close(); } else if (frame instanceof PingWebSocketFrame) { System.out.println("WebSocket Client received ping, response with pong"); ch.write(new PongWebSocketFrame(frame.getBinaryData())); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { final Throwable t = e.getCause(); t.printStackTrace(); e.getChannel().close(); } } package-info.java000066400000000000000000000016701225554127700337610ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/client/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** *

This is an example web service client. *

To run this example, you must first start * {@link org.jboss.netty.example.http.websocketx.server.WebSocketServer} and then * {@link org.jboss.netty.example.http.websocketx.client.WebSocketClient}. */ package org.jboss.netty.example.http.websocketx.client; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/html5/000077500000000000000000000000001225554127700304205ustar00rootroot00000000000000CustomTextFrameHandler.java000066400000000000000000000024711225554127700356000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/html5/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jboss.netty.example.http.websocketx.html5; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; public class CustomTextFrameHandler extends SimpleChannelHandler { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof TextWebSocketFrame) { TextWebSocketFrame frame = (TextWebSocketFrame) e.getMessage(); ctx.getChannel().write(new TextWebSocketFrame(frame.getText().toUpperCase())); } } } WebSocketServer.java000066400000000000000000000050711225554127700342640ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/html5/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jboss.netty.example.http.websocketx.html5; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.example.http.websocketx.server.WebSocketServerPipelineFactory; /** * A WebSocket Server that respondes to requests at: * *

 * http://localhost:8080/websocket
 * 
* * The example differs from many of the other examples in Netty in that is does * not have an acomponying client. Instead a html page is provided that * interacts with this server.
* Open up the following file a web browser that supports WebSocket's: * *
 * netty/src/test/resources/websocketx/html5/websocket.html
 * 
* * The html page is very simple were you simply enter some text and the server * will echo the same text back, but in uppercase. You, also see status messages * in the "Response From Server" area when client has connected, disconnected * etc. * */ public class WebSocketServer { private final int port; public WebSocketServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); System.out.println("Web socket server started at port " + port + '.'); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new WebSocketServer(port).run(); } } WebSocketServerPipelineFactory.java000066400000000000000000000033321225554127700373000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/html5/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.html5; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; public class WebSocketServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("handler", new WebSocketServerProtocolHandler("/websocket")); pipeline.addLast("testFramehandler", new CustomTextFrameHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/server/000077500000000000000000000000001225554127700306755ustar00rootroot00000000000000WebSocketServer.java000066400000000000000000000051641225554127700345440ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/server/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.server; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * A HTTP server which serves Web Socket requests at: * * http://localhost:8080/websocket * * Open your browser at http://localhost:8080/, then the demo page will be loaded and a Web Socket connection will be * made automatically. * * This server illustrates support for the different web socket specification versions and will work with: * *
    *
  • Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) *
  • Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) *
  • Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) *
  • Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) *
  • Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) *
  • Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) *
*/ public class WebSocketServer { private final int port; public WebSocketServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); System.out.println("Web socket server started at port " + port + '.'); System.out.println("Open your browser and navigate to http://localhost:" + port + '/'); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new WebSocketServer(port).run(); } } WebSocketServerHandler.java000066400000000000000000000145231225554127700360410ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/server/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.server; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import static org.jboss.netty.handler.codec.http.HttpMethod.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** * Handles handshakes and messages */ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandler.class); private static final String WEBSOCKET_PATH = "/websocket"; private WebSocketServerHandshaker handshaker; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpRequest) { handleHttpRequest(ctx, (HttpRequest) msg); } else if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); } } private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page and favicon.ico if ("/".equals(req.getUri())) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8"); setContentLength(res, content.readableBytes()); res.setContent(content); sendHttpResponse(ctx, req, res); return; } if ("/favicon.ico".equals(req.getUri())) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); sendHttpResponse(ctx, req, res); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( getWebSocketLocation(req), null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); } else { handshaker.handshake(ctx.getChannel(), req).addListener(WebSocketServerHandshaker.HANDSHAKE_LISTENER); } } private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { // Check for closing frame if (frame instanceof CloseWebSocketFrame) { handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); return; } if (frame instanceof PingWebSocketFrame) { ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); return; } if (!(frame instanceof TextWebSocketFrame)) { throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() .getName())); } // Send the uppercase string back. String request = ((TextWebSocketFrame) frame).getText(); if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request)); } ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); } private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { // Generate an error page if response status code is not OK (200). if (res.getStatus().getCode() != 200) { res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); setContentLength(res, res.getContent().readableBytes()); } // Send the response and close the connection if necessary. ChannelFuture f = ctx.getChannel().write(res); if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } private static String getWebSocketLocation(HttpRequest req) { return "ws://" + req.headers().get(HOST) + WEBSOCKET_PATH; } } WebSocketServerIndexPage.java000066400000000000000000000072551225554127700363340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/server/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.server; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.CharsetUtil; /** * Generates the demo HTML page which is served at http://localhost:8080/ */ public final class WebSocketServerIndexPage { private static final String NEWLINE = "\r\n"; public static ChannelBuffer getContent(String webSocketLocation) { return ChannelBuffers.copiedBuffer( "Web Socket Test" + NEWLINE + "" + NEWLINE + "" + NEWLINE + "
" + NEWLINE + "" + "" + NEWLINE + "

Output

" + NEWLINE + "" + NEWLINE + "
" + NEWLINE + "" + NEWLINE + "" + NEWLINE, CharsetUtil.US_ASCII); } private WebSocketServerIndexPage() { // Unused } } WebSocketServerPipelineFactory.java000066400000000000000000000030561225554127700375600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/server/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.server; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; /** */ public class WebSocketServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("handler", new WebSocketServerHandler()); return pipeline; } } package-info.java000066400000000000000000000021361225554127700340070ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/server/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** *

This package contains an example web socket web server. *

The web server only handles text, ping and closing frames. For text frames, * it echoes the received text in upper case. *

Once started, you can test the web server against your browser by navigating * to http://localhost:8080/ *

You can also test it with a web socket client. Send web socket traffic to * ws://localhost:8080/websocket. */ package org.jboss.netty.example.http.websocketx.server; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/sslserver/000077500000000000000000000000001225554127700314175ustar00rootroot00000000000000WebSocketSslServer.java000066400000000000000000000062211225554127700357430ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/sslserver/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.sslserver; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * A HTTP server which serves Web Socket requests at: * * https://localhost:8081/websocket * * Open your browser at https://localhost:8081/, then the demo page will be loaded and a Web Socket connection will be * made automatically. * * This server illustrates support for the different web socket specification versions and will work with: * *

    *
  • Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) *
  • Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) *
  • Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) *
  • Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) *
  • Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) *
*/ public class WebSocketSslServer { private final int port; public WebSocketSslServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new WebSocketSslServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); System.out.println("Web socket server started at port " + port + '.'); System.out.println("Open your browser and navigate to https://localhost:" + port + '/'); } public static void main(String[] args) { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8443; } String keyStoreFilePath = System.getProperty("keystore.file.path"); if (keyStoreFilePath == null || keyStoreFilePath.length() == 0) { System.out.println("ERROR: System property keystore.file.path not set. Exiting now!"); System.exit(1); } String keyStoreFilePassword = System.getProperty("keystore.file.password"); if (keyStoreFilePassword == null || keyStoreFilePassword.length() == 0) { System.out.println("ERROR: System property keystore.file.password not set. Exiting now!"); System.exit(1); } new WebSocketSslServer(port).run(); } } WebSocketSslServerHandler.java000066400000000000000000000146561225554127700372540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/sslserver/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.sslserver; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.example.http.websocketx.server.WebSocketServerIndexPage; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import static org.jboss.netty.handler.codec.http.HttpMethod.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** * Handles handshakes and messages */ public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerHandler.class); private static final String WEBSOCKET_PATH = "/websocket"; private WebSocketServerHandshaker handshaker; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpRequest) { handleHttpRequest(ctx, (HttpRequest) msg); } else if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); } } private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page and favicon.ico if ("/".equals(req.getUri())) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8"); setContentLength(res, content.readableBytes()); res.setContent(content); sendHttpResponse(ctx, req, res); return; } if ("/favicon.ico".equals(req.getUri())) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); sendHttpResponse(ctx, req, res); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( getWebSocketLocation(req), null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); } else { handshaker.handshake(ctx.getChannel(), req).addListener(WebSocketServerHandshaker.HANDSHAKE_LISTENER); } } private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { // Check for closing frame if (frame instanceof CloseWebSocketFrame) { handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); return; } if (frame instanceof PingWebSocketFrame) { ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); return; } if (!(frame instanceof TextWebSocketFrame)) { throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() .getName())); } // Send the uppercase string back. String request = ((TextWebSocketFrame) frame).getText(); if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request)); } ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); } private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { // Generate an error page if response status code is not OK (200). if (res.getStatus().getCode() != 200) { res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); setContentLength(res, res.getContent().readableBytes()); } // Send the response and close the connection if necessary. ChannelFuture f = ctx.getChannel().write(res); if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } private static String getWebSocketLocation(HttpRequest req) { return "wss://" + req.headers().get(HOST) + WEBSOCKET_PATH; } } WebSocketSslServerPipelineFactory.java000066400000000000000000000035261225554127700407660ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/sslserver/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.sslserver; import static org.jboss.netty.channel.Channels.*; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.ssl.SslHandler; /** */ public class WebSocketSslServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); SSLEngine engine = WebSocketSslServerSslContext.getInstance().getServerContext().createSSLEngine(); engine.setUseClientMode(false); pipeline.addLast("ssl", new SslHandler(engine)); pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("handler", new WebSocketSslServerHandler()); return pipeline; } } WebSocketSslServerSslContext.java000066400000000000000000000072351225554127700400000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/sslserver/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.http.websocketx.sslserver; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import java.io.FileInputStream; import java.security.KeyStore; import java.security.Security; /** * Creates a {@link SSLContext} for just server certificates. */ public final class WebSocketSslServerSslContext { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerSslContext.class); private static final String PROTOCOL = "TLS"; private final SSLContext _serverContext; /** * Returns the singleton instance for this class */ public static WebSocketSslServerSslContext getInstance() { return SingletonHolder.INSTANCE; } /** * SingletonHolder is loaded on the first execution of Singleton.getInstance() or the first access to * SingletonHolder.INSTANCE, not before. * * See http://en.wikipedia.org/wiki/Singleton_pattern */ private interface SingletonHolder { WebSocketSslServerSslContext INSTANCE = new WebSocketSslServerSslContext(); } /** * Constructor for singleton */ private WebSocketSslServerSslContext() { SSLContext serverContext = null; try { // Key store (Server side certificate) String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); if (algorithm == null) { algorithm = "SunX509"; } try { String keyStoreFilePath = System.getProperty("keystore.file.path"); String keyStoreFilePassword = System.getProperty("keystore.file.password"); KeyStore ks = KeyStore.getInstance("JKS"); FileInputStream fin = new FileInputStream(keyStoreFilePath); ks.load(fin, keyStoreFilePassword.toCharArray()); // Set up key manager factory to use our key store // Assume key password is the same as the key store file // password KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); kmf.init(ks, keyStoreFilePassword.toCharArray()); // Initialise the SSLContext to work with our key managers. serverContext = SSLContext.getInstance(PROTOCOL); serverContext.init(kmf.getKeyManagers(), null, null); } catch (Exception e) { throw new Error("Failed to initialize the server-side SSLContext", e); } } catch (Exception ex) { if (logger.isErrorEnabled()) { logger.error("Error initializing SslContextManager. " + ex.getMessage(), ex); } System.exit(1); } finally { _serverContext = serverContext; } } /** * Returns the server context with server side key store */ public SSLContext getServerContext() { return _serverContext; } } package-info.java000066400000000000000000000030721225554127700345310ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/http/websocketx/sslserver/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** *

This package contains an example web socket web server with server SSL. *

To run this example, follow the steps below: *

*
Step 1. Generate Your Key *
* {@code keytool -genkey -keystore mySrvKeystore -keyalg RSA}. * Make sure that you set the key password to be the same the key file password. *
Step 2. Specify your key store file and password as system properties *
* {@code -Dkeystore.file.path= -Dkeystore.file.password=} *
Step 3. Run WebSocketSslServer as a Java application *
* Once started, you can test the web server against your browser by navigating to https://localhost:8081/ *
*

To find out more about setting up key stores, refer to this * giude. */ package org.jboss.netty.example.http.websocketx.sslserver; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/local/000077500000000000000000000000001225554127700253245ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/local/LocalExample.java000066400000000000000000000077371225554127700305530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.local; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.local.DefaultLocalClientChannelFactory; import org.jboss.netty.channel.local.DefaultLocalServerChannelFactory; import org.jboss.netty.channel.local.LocalAddress; import org.jboss.netty.example.echo.EchoServerHandler; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.logging.LoggingHandler; import org.jboss.netty.logging.InternalLogLevel; public class LocalExample { private final String port; public LocalExample(String port) { this.port = port; } public void run() throws IOException { // Address to bind on / connect to. LocalAddress socketAddress = new LocalAddress(port); // Configure the server. ServerBootstrap sb = new ServerBootstrap( new DefaultLocalServerChannelFactory()); // Set up the default server-side event pipeline. EchoServerHandler handler = new EchoServerHandler(); sb.getPipeline().addLast("handler", handler); // Start up the server. sb.bind(socketAddress); // Configure the client. ClientBootstrap cb = new ClientBootstrap( new DefaultLocalClientChannelFactory()); // Set up the client-side pipeline factory. cb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringDecoder(), new StringEncoder(), new LoggingHandler(InternalLogLevel.INFO)); } }); // Make the connection attempt to the server. ChannelFuture channelFuture = cb.connect(socketAddress); channelFuture.awaitUninterruptibly(); // Read commands from the stdin. System.out.println("Enter text (quit to end)"); ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (; ;) { String line = in.readLine(); if (line == null || "quit".equalsIgnoreCase(line)) { break; } // Sends the received line to the server. lastWriteFuture = channelFuture.getChannel().write(line); } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.awaitUninterruptibly(); } channelFuture.getChannel().close(); // Wait until the connection is closed or the connection attempt fails. channelFuture.getChannel().getCloseFuture().awaitUninterruptibly(); // Release all resources used by the local transport. cb.releaseExternalResources(); sb.releaseExternalResources(); } public static void main(String[] args) throws Exception { new LocalExample("1").run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/local/LocalExampleMultithreaded.java000066400000000000000000000100211225554127700332430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.local; import java.util.concurrent.TimeUnit; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.local.DefaultLocalClientChannelFactory; import org.jboss.netty.channel.local.DefaultLocalServerChannelFactory; import org.jboss.netty.channel.local.LocalAddress; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; import org.jboss.netty.handler.logging.LoggingHandler; import org.jboss.netty.logging.InternalLogLevel; public class LocalExampleMultithreaded { private final String port; public LocalExampleMultithreaded(String port) { this.port = port; } public void run() { LocalAddress socketAddress = new LocalAddress(port); OrderedMemoryAwareThreadPoolExecutor eventExecutor = new OrderedMemoryAwareThreadPoolExecutor( 5, 1000000, 10000000, 100, TimeUnit.MILLISECONDS); ServerBootstrap sb = new ServerBootstrap( new DefaultLocalServerChannelFactory()); sb.setPipelineFactory(new LocalServerPipelineFactory(eventExecutor)); sb.bind(socketAddress); ClientBootstrap cb = new ClientBootstrap( new DefaultLocalClientChannelFactory()); cb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringDecoder(), new StringEncoder(), new LoggingHandler(InternalLogLevel.INFO)); } }); // Read commands from array String[] commands = { "First", "Second", "Third", "quit" }; for (int j = 0; j < 5 ; j++) { System.err.println("Start " + j); ChannelFuture channelFuture = cb.connect(socketAddress); channelFuture.awaitUninterruptibly(); if (! channelFuture.isSuccess()) { System.err.println("CANNOT CONNECT"); channelFuture.getCause().printStackTrace(); break; } ChannelFuture lastWriteFuture = null; for (String line: commands) { // Sends the received line to the server. lastWriteFuture = channelFuture.getChannel().write(line); } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.awaitUninterruptibly(); } channelFuture.getChannel().close(); // Wait until the connection is closed or the connection attempt fails. channelFuture.getChannel().getCloseFuture().awaitUninterruptibly(); System.err.println("End " + j); } // Release all resources cb.releaseExternalResources(); sb.releaseExternalResources(); eventExecutor.shutdownNow(); } public static void main(String[] args) throws Exception { new LocalExampleMultithreaded("1").run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/local/LocalServerPipelineFactory.java000066400000000000000000000060711225554127700334320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.local; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.execution.ExecutionHandler; import java.util.concurrent.Executor; public class LocalServerPipelineFactory implements ChannelPipelineFactory { private final ExecutionHandler executionHandler; public LocalServerPipelineFactory(Executor eventExecutor) { executionHandler = new ExecutionHandler(eventExecutor); } public ChannelPipeline getPipeline() throws Exception { final ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("executor", executionHandler); pipeline.addLast("handler", new EchoCloseServerHandler()); return pipeline; } static class EchoCloseServerHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler { public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof MessageEvent) { final MessageEvent evt = (MessageEvent) e; String msg = (String) evt.getMessage(); if ("quit".equalsIgnoreCase(msg)) { Channels.close(e.getChannel()); return; } } ctx.sendUpstream(e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) { if (e instanceof MessageEvent) { final MessageEvent evt = (MessageEvent) e; String msg = (String) evt.getMessage(); if ("quit".equalsIgnoreCase(msg)) { Channels.close(e.getChannel()); return; } System.err.println("SERVER:" + msg); // Write back Channels.write(e.getChannel(), msg); } ctx.sendDownstream(e); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/000077500000000000000000000000001225554127700262035ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/LocalTimeClient.java000066400000000000000000000104301225554127700320540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.concurrent.Executors; import java.util.regex.Pattern; /** * Sends a list of continent/city pairs to a {@link LocalTimeServer} to * get the local times of the specified cities. */ public class LocalTimeClient { private final String host; private final int port; private final Collection cities; public LocalTimeClient(String host, int port, Collection cities) { this.host = host; this.port = port; this.cities = new ArrayList(); this.cities.addAll(cities); } public void run() { // Set up. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Configure the event pipeline factory. bootstrap.setPipelineFactory(new LocalTimeClientPipelineFactory()); // Make a new connection. ChannelFuture connectFuture = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection is made successfully. Channel channel = connectFuture.awaitUninterruptibly().getChannel(); // Get the handler instance to initiate the request. LocalTimeClientHandler handler = channel.getPipeline().get(LocalTimeClientHandler.class); // Request and get the response. List response = handler.getLocalTimes(cities); // Close the connection. channel.close().awaitUninterruptibly(); // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); // Print the response at last but not least. Iterator i1 = cities.iterator(); Iterator i2 = response.iterator(); while (i1.hasNext()) { System.out.format("%28s: %s%n", i1.next(), i2.next()); } } public static void main(String[] args) throws Exception { // Print usage if necessary. if (args.length < 3) { printUsage(); return; } // Parse options. String host = args[0]; int port = Integer.parseInt(args[1]); Collection cities = parseCities(args, 2); if (cities == null) { return; } new LocalTimeClient(host, port, cities).run(); } private static void printUsage() { System.err.println( "Usage: " + LocalTimeClient.class.getSimpleName() + " ..."); System.err.println( "Example: " + LocalTimeClient.class.getSimpleName() + " localhost 8080 America/New_York Asia/Seoul"); } private static final Pattern CITY_PATTERN = Pattern.compile("^[_A-Za-z]+/[_A-Za-z]+$"); private static List parseCities(String[] args, int offset) { List cities = new ArrayList(); for (int i = offset; i < args.length; i ++) { if (!CITY_PATTERN.matcher(args[i]).matches()) { System.err.println("Syntax error: '" + args[i] + '\''); printUsage(); return null; } cities.add(args[i].trim()); } return cities; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/LocalTimeClientHandler.java000066400000000000000000000105551225554127700333620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.example.localtime.LocalTimeProtocol.Continent; import org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime; import org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes; import org.jboss.netty.example.localtime.LocalTimeProtocol.Location; import org.jboss.netty.example.localtime.LocalTimeProtocol.Locations; import java.util.ArrayList; import java.util.Collection; import java.util.Formatter; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( LocalTimeClientHandler.class.getName()); private static final Pattern DELIM = Pattern.compile("/"); // Stateful properties private volatile Channel channel; private final BlockingQueue answer = new LinkedBlockingQueue(); public List getLocalTimes(Collection cities) { Locations.Builder builder = Locations.newBuilder(); for (String c: cities) { String[] components = DELIM.split(c); builder.addLocation(Location.newBuilder(). setContinent(Continent.valueOf(components[0].toUpperCase())). setCity(components[1]).build()); } channel.write(builder.build()); LocalTimes localTimes; boolean interrupted = false; for (;;) { try { localTimes = answer.take(); break; } catch (InterruptedException e) { interrupted = true; } } if (interrupted) { Thread.currentThread().interrupt(); } List result = new ArrayList(); for (LocalTime lt: localTimes.getLocalTimeList()) { result.add( new Formatter().format( "%4d-%02d-%02d %02d:%02d:%02d %s", lt.getYear(), lt.getMonth(), lt.getDayOfMonth(), lt.getHour(), lt.getMinute(), lt.getSecond(), lt.getDayOfWeek().name()).toString()); } return result; } @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); super.channelOpen(ctx, e); } @Override public void messageReceived( ChannelHandlerContext ctx, final MessageEvent e) { boolean offered = answer.offer((LocalTimes) e.getMessage()); assert offered; } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } LocalTimeClientPipelineFactory.java000066400000000000000000000032561225554127700350230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; public class LocalTimeClientPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline p = pipeline(); p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); p.addLast("protobufDecoder", new ProtobufDecoder(LocalTimeProtocol.LocalTimes.getDefaultInstance())); p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender()); p.addLast("protobufEncoder", new ProtobufEncoder()); p.addLast("handler", new LocalTimeClientHandler()); return p; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/LocalTimeProtocol.java000066400000000000000000003010631225554127700324440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: src/main/java/org/jboss/netty/example/localtime/LocalTimeProtocol.proto package org.jboss.netty.example.localtime; @SuppressWarnings("all") public final class LocalTimeProtocol { private LocalTimeProtocol() {} public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { } public enum Continent implements com.google.protobuf.ProtocolMessageEnum { AFRICA(0, 0), AMERICA(1, 1), ANTARCTICA(2, 2), ARCTIC(3, 3), ASIA(4, 4), ATLANTIC(5, 5), AUSTRALIA(6, 6), EUROPE(7, 7), INDIAN(8, 8), MIDEAST(9, 9), PACIFIC(10, 10), ; public static final int AFRICA_VALUE = 0; public static final int AMERICA_VALUE = 1; public static final int ANTARCTICA_VALUE = 2; public static final int ARCTIC_VALUE = 3; public static final int ASIA_VALUE = 4; public static final int ATLANTIC_VALUE = 5; public static final int AUSTRALIA_VALUE = 6; public static final int EUROPE_VALUE = 7; public static final int INDIAN_VALUE = 8; public static final int MIDEAST_VALUE = 9; public static final int PACIFIC_VALUE = 10; public final int getNumber() { return value; } public static Continent valueOf(int value) { switch (value) { case 0: return AFRICA; case 1: return AMERICA; case 2: return ANTARCTICA; case 3: return ARCTIC; case 4: return ASIA; case 5: return ATLANTIC; case 6: return AUSTRALIA; case 7: return EUROPE; case 8: return INDIAN; case 9: return MIDEAST; case 10: return PACIFIC; default: return null; } } public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { return internalValueMap; } private static com.google.protobuf.Internal.EnumLiteMap internalValueMap = new com.google.protobuf.Internal.EnumLiteMap() { public Continent findValueByNumber(int number) { return Continent.valueOf(number); } }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { return getDescriptor().getValues().get(index); } public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { return getDescriptor(); } public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.getDescriptor().getEnumTypes().get(0); } private static final Continent[] VALUES = { AFRICA, AMERICA, ANTARCTICA, ARCTIC, ASIA, ATLANTIC, AUSTRALIA, EUROPE, INDIAN, MIDEAST, PACIFIC, }; public static Continent valueOf( com.google.protobuf.Descriptors.EnumValueDescriptor desc) { if (desc.getType() != getDescriptor()) { throw new java.lang.IllegalArgumentException( "EnumValueDescriptor is not for this type."); } return VALUES[desc.getIndex()]; } private final int index; private final int value; private Continent(int index, int value) { this.index = index; this.value = value; } // @@protoc_insertion_point(enum_scope:org.jboss.netty.example.localtime.Continent) } public enum DayOfWeek implements com.google.protobuf.ProtocolMessageEnum { SUNDAY(0, 1), MONDAY(1, 2), TUESDAY(2, 3), WEDNESDAY(3, 4), THURSDAY(4, 5), FRIDAY(5, 6), SATURDAY(6, 7), ; public static final int SUNDAY_VALUE = 1; public static final int MONDAY_VALUE = 2; public static final int TUESDAY_VALUE = 3; public static final int WEDNESDAY_VALUE = 4; public static final int THURSDAY_VALUE = 5; public static final int FRIDAY_VALUE = 6; public static final int SATURDAY_VALUE = 7; public final int getNumber() { return value; } public static DayOfWeek valueOf(int value) { switch (value) { case 1: return SUNDAY; case 2: return MONDAY; case 3: return TUESDAY; case 4: return WEDNESDAY; case 5: return THURSDAY; case 6: return FRIDAY; case 7: return SATURDAY; default: return null; } } public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { return internalValueMap; } private static com.google.protobuf.Internal.EnumLiteMap internalValueMap = new com.google.protobuf.Internal.EnumLiteMap() { public DayOfWeek findValueByNumber(int number) { return DayOfWeek.valueOf(number); } }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { return getDescriptor().getValues().get(index); } public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { return getDescriptor(); } public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.getDescriptor().getEnumTypes().get(1); } private static final DayOfWeek[] VALUES = { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, }; public static DayOfWeek valueOf( com.google.protobuf.Descriptors.EnumValueDescriptor desc) { if (desc.getType() != getDescriptor()) { throw new java.lang.IllegalArgumentException( "EnumValueDescriptor is not for this type."); } return VALUES[desc.getIndex()]; } private final int index; private final int value; private DayOfWeek(int index, int value) { this.index = index; this.value = value; } // @@protoc_insertion_point(enum_scope:org.jboss.netty.example.localtime.DayOfWeek) } public interface LocationOrBuilder extends com.google.protobuf.MessageOrBuilder { // required .org.jboss.netty.example.localtime.Continent continent = 1; boolean hasContinent(); org.jboss.netty.example.localtime.LocalTimeProtocol.Continent getContinent(); // required string city = 2; boolean hasCity(); String getCity(); } public static final class Location extends com.google.protobuf.GeneratedMessage implements LocationOrBuilder { // Use Location.newBuilder() to construct. private Location(Builder builder) { super(builder); } private Location(boolean noInit) {} private static final Location defaultInstance; public static Location getDefaultInstance() { return defaultInstance; } public Location getDefaultInstanceForType() { return defaultInstance; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Location_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Location_fieldAccessorTable; } private int bitField0_; // required .org.jboss.netty.example.localtime.Continent continent = 1; public static final int CONTINENT_FIELD_NUMBER = 1; private org.jboss.netty.example.localtime.LocalTimeProtocol.Continent continent_; public boolean hasContinent() { return (bitField0_ & 0x00000001) == 0x00000001; } public org.jboss.netty.example.localtime.LocalTimeProtocol.Continent getContinent() { return continent_; } // required string city = 2; public static final int CITY_FIELD_NUMBER = 2; private java.lang.Object city_; public boolean hasCity() { return (bitField0_ & 0x00000002) == 0x00000002; } public String getCity() { java.lang.Object ref = city_; if (ref instanceof String) { return (String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); if (com.google.protobuf.Internal.isValidUtf8(bs)) { city_ = s; } return s; } } private com.google.protobuf.ByteString getCityBytes() { java.lang.Object ref = city_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); city_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } private void initFields() { continent_ = org.jboss.netty.example.localtime.LocalTimeProtocol.Continent.AFRICA; city_ = ""; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) { return isInitialized == 1; } if (!hasContinent()) { memoizedIsInitialized = 0; return false; } if (!hasCity()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); if ((bitField0_ & 0x00000001) == 0x00000001) { output.writeEnum(1, continent_.getNumber()); } if ((bitField0_ & 0x00000002) == 0x00000002) { output.writeBytes(2, getCityBytes()); } getUnknownFields().writeTo(output); } private int memoizedSerializedSize = -1; public int getSerializedSize() { int size = memoizedSerializedSize; if (size != -1) { return size; } size = 0; if ((bitField0_ & 0x00000001) == 0x00000001) { size += com.google.protobuf.CodedOutputStream .computeEnumSize(1, continent_.getNumber()); } if ((bitField0_ & 0x00000002) == 0x00000002) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(2, getCityBytes()); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; } private static final long serialVersionUID = 0L; @java.lang.Override protected java.lang.Object writeReplace() throws java.io.ObjectStreamException { return super.writeReplace(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input, extensionRegistry)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Location parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder(org.jboss.netty.example.localtime.LocalTimeProtocol.Location prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Location_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Location_fieldAccessorTable; } // Construct using org.jboss.netty.example.localtime.LocalTimeProtocol.Location.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder(BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { } } private static Builder create() { return new Builder(); } public Builder clear() { super.clear(); continent_ = org.jboss.netty.example.localtime.LocalTimeProtocol.Continent.AFRICA; bitField0_ = bitField0_ & ~0x00000001; city_ = ""; bitField0_ = bitField0_ & ~0x00000002; return this; } public Builder clone() { return create().mergeFrom(buildPartial()); } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.Location.getDescriptor(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location getDefaultInstanceForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.Location.getDefaultInstance(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location build() { org.jboss.netty.example.localtime.LocalTimeProtocol.Location result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } private org.jboss.netty.example.localtime.LocalTimeProtocol.Location buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { org.jboss.netty.example.localtime.LocalTimeProtocol.Location result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); } return result; } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location buildPartial() { org.jboss.netty.example.localtime.LocalTimeProtocol.Location result = new org.jboss.netty.example.localtime.LocalTimeProtocol.Location(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if ((from_bitField0_ & 0x00000001) == 0x00000001) { to_bitField0_ |= 0x00000001; } result.continent_ = continent_; if ((from_bitField0_ & 0x00000002) == 0x00000002) { to_bitField0_ |= 0x00000002; } result.city_ = city_; result.bitField0_ = to_bitField0_; onBuilt(); return result; } public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.jboss.netty.example.localtime.LocalTimeProtocol.Location) { return mergeFrom((org.jboss.netty.example.localtime.LocalTimeProtocol.Location)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.jboss.netty.example.localtime.LocalTimeProtocol.Location other) { if (other == org.jboss.netty.example.localtime.LocalTimeProtocol.Location.getDefaultInstance()) { return this; } if (other.hasContinent()) { setContinent(other.getContinent()); } if (other.hasCity()) { setCity(other.getCity()); } mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { if (!hasContinent()) { return false; } if (!hasCity()) { return false; } return true; } public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder( getUnknownFields()); while (true) { int tag = input.readTag(); switch (tag) { case 0: setUnknownFields(unknownFields.build()); onChanged(); return this; default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { setUnknownFields(unknownFields.build()); onChanged(); return this; } break; } case 8: { int rawValue = input.readEnum(); org.jboss.netty.example.localtime.LocalTimeProtocol.Continent value = org.jboss.netty.example.localtime.LocalTimeProtocol.Continent.valueOf(rawValue); if (value == null) { unknownFields.mergeVarintField(1, rawValue); } else { bitField0_ |= 0x00000001; continent_ = value; } break; } case 18: { bitField0_ |= 0x00000002; city_ = input.readBytes(); break; } } } } private int bitField0_; // required .org.jboss.netty.example.localtime.Continent continent = 1; private org.jboss.netty.example.localtime.LocalTimeProtocol.Continent continent_ = org.jboss.netty.example.localtime.LocalTimeProtocol.Continent.AFRICA; public boolean hasContinent() { return (bitField0_ & 0x00000001) == 0x00000001; } public org.jboss.netty.example.localtime.LocalTimeProtocol.Continent getContinent() { return continent_; } public Builder setContinent(org.jboss.netty.example.localtime.LocalTimeProtocol.Continent value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000001; continent_ = value; onChanged(); return this; } public Builder clearContinent() { bitField0_ = bitField0_ & ~0x00000001; continent_ = org.jboss.netty.example.localtime.LocalTimeProtocol.Continent.AFRICA; onChanged(); return this; } // required string city = 2; private java.lang.Object city_ = ""; public boolean hasCity() { return (bitField0_ & 0x00000002) == 0x00000002; } public String getCity() { java.lang.Object ref = city_; if (!(ref instanceof String)) { String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); city_ = s; return s; } else { return (String) ref; } } public Builder setCity(String value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000002; city_ = value; onChanged(); return this; } public Builder clearCity() { bitField0_ = bitField0_ & ~0x00000002; city_ = getDefaultInstance().getCity(); onChanged(); return this; } void setCity(com.google.protobuf.ByteString value) { bitField0_ |= 0x00000002; city_ = value; onChanged(); } // @@protoc_insertion_point(builder_scope:org.jboss.netty.example.localtime.Location) } static { defaultInstance = new Location(true); defaultInstance.initFields(); } // @@protoc_insertion_point(class_scope:org.jboss.netty.example.localtime.Location) } public interface LocationsOrBuilder extends com.google.protobuf.MessageOrBuilder { // repeated .org.jboss.netty.example.localtime.Location location = 1; java.util.List getLocationList(); org.jboss.netty.example.localtime.LocalTimeProtocol.Location getLocation(int index); int getLocationCount(); java.util.List getLocationOrBuilderList(); org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder getLocationOrBuilder( int index); } public static final class Locations extends com.google.protobuf.GeneratedMessage implements LocationsOrBuilder { // Use Locations.newBuilder() to construct. private Locations(Builder builder) { super(builder); } private Locations(boolean noInit) {} private static final Locations defaultInstance; public static Locations getDefaultInstance() { return defaultInstance; } public Locations getDefaultInstanceForType() { return defaultInstance; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Locations_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Locations_fieldAccessorTable; } // repeated .org.jboss.netty.example.localtime.Location location = 1; public static final int LOCATION_FIELD_NUMBER = 1; private java.util.List location_; public java.util.List getLocationList() { return location_; } public java.util.List getLocationOrBuilderList() { return location_; } public int getLocationCount() { return location_.size(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location getLocation(int index) { return location_.get(index); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder getLocationOrBuilder( int index) { return location_.get(index); } private void initFields() { location_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) { return isInitialized == 1; } for (int i = 0; i < getLocationCount(); i++) { if (!getLocation(i).isInitialized()) { memoizedIsInitialized = 0; return false; } } memoizedIsInitialized = 1; return true; } public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); for (int i = 0; i < location_.size(); i++) { output.writeMessage(1, location_.get(i)); } getUnknownFields().writeTo(output); } private int memoizedSerializedSize = -1; public int getSerializedSize() { int size = memoizedSerializedSize; if (size != -1) { return size; } size = 0; for (int i = 0; i < location_.size(); i++) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(1, location_.get(i)); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; } private static final long serialVersionUID = 0L; @java.lang.Override protected java.lang.Object writeReplace() throws java.io.ObjectStreamException { return super.writeReplace(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input, extensionRegistry)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.Locations parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder(org.jboss.netty.example.localtime.LocalTimeProtocol.Locations prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements org.jboss.netty.example.localtime.LocalTimeProtocol.LocationsOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Locations_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_Locations_fieldAccessorTable; } // Construct using org.jboss.netty.example.localtime.LocalTimeProtocol.Locations.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder(BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { getLocationFieldBuilder(); } } private static Builder create() { return new Builder(); } public Builder clear() { super.clear(); if (locationBuilder_ == null) { location_ = java.util.Collections.emptyList(); bitField0_ = bitField0_ & ~0x00000001; } else { locationBuilder_.clear(); } return this; } public Builder clone() { return create().mergeFrom(buildPartial()); } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.Locations.getDescriptor(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.Locations getDefaultInstanceForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.Locations.getDefaultInstance(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.Locations build() { org.jboss.netty.example.localtime.LocalTimeProtocol.Locations result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } private org.jboss.netty.example.localtime.LocalTimeProtocol.Locations buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { org.jboss.netty.example.localtime.LocalTimeProtocol.Locations result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); } return result; } public org.jboss.netty.example.localtime.LocalTimeProtocol.Locations buildPartial() { org.jboss.netty.example.localtime.LocalTimeProtocol.Locations result = new org.jboss.netty.example.localtime.LocalTimeProtocol.Locations(this); int from_bitField0_ = bitField0_; if (locationBuilder_ == null) { if ((bitField0_ & 0x00000001) == 0x00000001) { location_ = java.util.Collections.unmodifiableList(location_); bitField0_ = bitField0_ & ~0x00000001; } result.location_ = location_; } else { result.location_ = locationBuilder_.build(); } onBuilt(); return result; } public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.jboss.netty.example.localtime.LocalTimeProtocol.Locations) { return mergeFrom((org.jboss.netty.example.localtime.LocalTimeProtocol.Locations)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.jboss.netty.example.localtime.LocalTimeProtocol.Locations other) { if (other == org.jboss.netty.example.localtime.LocalTimeProtocol.Locations.getDefaultInstance()) { return this; } if (locationBuilder_ == null) { if (!other.location_.isEmpty()) { if (location_.isEmpty()) { location_ = other.location_; bitField0_ = bitField0_ & ~0x00000001; } else { ensureLocationIsMutable(); location_.addAll(other.location_); } onChanged(); } } else { if (!other.location_.isEmpty()) { if (locationBuilder_.isEmpty()) { locationBuilder_.dispose(); locationBuilder_ = null; location_ = other.location_; bitField0_ = bitField0_ & ~0x00000001; locationBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getLocationFieldBuilder() : null; } else { locationBuilder_.addAllMessages(other.location_); } } } mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { for (int i = 0; i < getLocationCount(); i++) { if (!getLocation(i).isInitialized()) { return false; } } return true; } public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder( getUnknownFields()); while (true) { int tag = input.readTag(); switch (tag) { case 0: setUnknownFields(unknownFields.build()); onChanged(); return this; default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { setUnknownFields(unknownFields.build()); onChanged(); return this; } break; } case 10: { org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder subBuilder = org.jboss.netty.example.localtime.LocalTimeProtocol.Location.newBuilder(); input.readMessage(subBuilder, extensionRegistry); addLocation(subBuilder.buildPartial()); break; } } } } private int bitField0_; // repeated .org.jboss.netty.example.localtime.Location location = 1; private java.util.List location_ = java.util.Collections.emptyList(); private void ensureLocationIsMutable() { if (!((bitField0_ & 0x00000001) == 0x00000001)) { location_ = new java.util.ArrayList(location_); bitField0_ |= 0x00000001; } } private com.google.protobuf.RepeatedFieldBuilder< org.jboss.netty.example.localtime.LocalTimeProtocol.Location, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder, org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder> locationBuilder_; public java.util.List getLocationList() { if (locationBuilder_ == null) { return java.util.Collections.unmodifiableList(location_); } else { return locationBuilder_.getMessageList(); } } public int getLocationCount() { if (locationBuilder_ == null) { return location_.size(); } else { return locationBuilder_.getCount(); } } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location getLocation(int index) { if (locationBuilder_ == null) { return location_.get(index); } else { return locationBuilder_.getMessage(index); } } public Builder setLocation( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.Location value) { if (locationBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureLocationIsMutable(); location_.set(index, value); onChanged(); } else { locationBuilder_.setMessage(index, value); } return this; } public Builder setLocation( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder builderForValue) { if (locationBuilder_ == null) { ensureLocationIsMutable(); location_.set(index, builderForValue.build()); onChanged(); } else { locationBuilder_.setMessage(index, builderForValue.build()); } return this; } public Builder addLocation(org.jboss.netty.example.localtime.LocalTimeProtocol.Location value) { if (locationBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureLocationIsMutable(); location_.add(value); onChanged(); } else { locationBuilder_.addMessage(value); } return this; } public Builder addLocation( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.Location value) { if (locationBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureLocationIsMutable(); location_.add(index, value); onChanged(); } else { locationBuilder_.addMessage(index, value); } return this; } public Builder addLocation( org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder builderForValue) { if (locationBuilder_ == null) { ensureLocationIsMutable(); location_.add(builderForValue.build()); onChanged(); } else { locationBuilder_.addMessage(builderForValue.build()); } return this; } public Builder addLocation( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder builderForValue) { if (locationBuilder_ == null) { ensureLocationIsMutable(); location_.add(index, builderForValue.build()); onChanged(); } else { locationBuilder_.addMessage(index, builderForValue.build()); } return this; } public Builder addAllLocation( java.lang.Iterable values) { if (locationBuilder_ == null) { ensureLocationIsMutable(); super.addAll(values, location_); onChanged(); } else { locationBuilder_.addAllMessages(values); } return this; } public Builder clearLocation() { if (locationBuilder_ == null) { location_ = java.util.Collections.emptyList(); bitField0_ = bitField0_ & ~0x00000001; onChanged(); } else { locationBuilder_.clear(); } return this; } public Builder removeLocation(int index) { if (locationBuilder_ == null) { ensureLocationIsMutable(); location_.remove(index); onChanged(); } else { locationBuilder_.remove(index); } return this; } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder getLocationBuilder( int index) { return getLocationFieldBuilder().getBuilder(index); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder getLocationOrBuilder( int index) { if (locationBuilder_ == null) { return location_.get(index); } else { return locationBuilder_.getMessageOrBuilder(index); } } public java.util.List getLocationOrBuilderList() { if (locationBuilder_ != null) { return locationBuilder_.getMessageOrBuilderList(); } else { return java.util.Collections.unmodifiableList(location_); } } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder addLocationBuilder() { return getLocationFieldBuilder().addBuilder( org.jboss.netty.example.localtime.LocalTimeProtocol.Location.getDefaultInstance()); } public org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder addLocationBuilder( int index) { return getLocationFieldBuilder().addBuilder( index, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.getDefaultInstance()); } public java.util.List getLocationBuilderList() { return getLocationFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< org.jboss.netty.example.localtime.LocalTimeProtocol.Location, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder, org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder> getLocationFieldBuilder() { if (locationBuilder_ == null) { locationBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< org.jboss.netty.example.localtime.LocalTimeProtocol.Location, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder, org.jboss.netty.example.localtime.LocalTimeProtocol.LocationOrBuilder>( location_, (bitField0_ & 0x00000001) == 0x00000001, getParentForChildren(), isClean()); location_ = null; } return locationBuilder_; } // @@protoc_insertion_point(builder_scope:org.jboss.netty.example.localtime.Locations) } static { defaultInstance = new Locations(true); defaultInstance.initFields(); } // @@protoc_insertion_point(class_scope:org.jboss.netty.example.localtime.Locations) } public interface LocalTimeOrBuilder extends com.google.protobuf.MessageOrBuilder { // required uint32 year = 1; boolean hasYear(); int getYear(); // required uint32 month = 2; boolean hasMonth(); int getMonth(); // required uint32 dayOfMonth = 4; boolean hasDayOfMonth(); int getDayOfMonth(); // required .org.jboss.netty.example.localtime.DayOfWeek dayOfWeek = 5; boolean hasDayOfWeek(); org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek getDayOfWeek(); // required uint32 hour = 6; boolean hasHour(); int getHour(); // required uint32 minute = 7; boolean hasMinute(); int getMinute(); // required uint32 second = 8; boolean hasSecond(); int getSecond(); } public static final class LocalTime extends com.google.protobuf.GeneratedMessage implements LocalTimeOrBuilder { // Use LocalTime.newBuilder() to construct. private LocalTime(Builder builder) { super(builder); } private LocalTime(boolean noInit) {} private static final LocalTime defaultInstance; public static LocalTime getDefaultInstance() { return defaultInstance; } public LocalTime getDefaultInstanceForType() { return defaultInstance; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTime_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTime_fieldAccessorTable; } private int bitField0_; // required uint32 year = 1; public static final int YEAR_FIELD_NUMBER = 1; private int year_; public boolean hasYear() { return (bitField0_ & 0x00000001) == 0x00000001; } public int getYear() { return year_; } // required uint32 month = 2; public static final int MONTH_FIELD_NUMBER = 2; private int month_; public boolean hasMonth() { return (bitField0_ & 0x00000002) == 0x00000002; } public int getMonth() { return month_; } // required uint32 dayOfMonth = 4; public static final int DAYOFMONTH_FIELD_NUMBER = 4; private int dayOfMonth_; public boolean hasDayOfMonth() { return (bitField0_ & 0x00000004) == 0x00000004; } public int getDayOfMonth() { return dayOfMonth_; } // required .org.jboss.netty.example.localtime.DayOfWeek dayOfWeek = 5; public static final int DAYOFWEEK_FIELD_NUMBER = 5; private org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek dayOfWeek_; public boolean hasDayOfWeek() { return (bitField0_ & 0x00000008) == 0x00000008; } public org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek getDayOfWeek() { return dayOfWeek_; } // required uint32 hour = 6; public static final int HOUR_FIELD_NUMBER = 6; private int hour_; public boolean hasHour() { return (bitField0_ & 0x00000010) == 0x00000010; } public int getHour() { return hour_; } // required uint32 minute = 7; public static final int MINUTE_FIELD_NUMBER = 7; private int minute_; public boolean hasMinute() { return (bitField0_ & 0x00000020) == 0x00000020; } public int getMinute() { return minute_; } // required uint32 second = 8; public static final int SECOND_FIELD_NUMBER = 8; private int second_; public boolean hasSecond() { return (bitField0_ & 0x00000040) == 0x00000040; } public int getSecond() { return second_; } private void initFields() { year_ = 0; month_ = 0; dayOfMonth_ = 0; dayOfWeek_ = org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek.SUNDAY; hour_ = 0; minute_ = 0; second_ = 0; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) { return isInitialized == 1; } if (!hasYear()) { memoizedIsInitialized = 0; return false; } if (!hasMonth()) { memoizedIsInitialized = 0; return false; } if (!hasDayOfMonth()) { memoizedIsInitialized = 0; return false; } if (!hasDayOfWeek()) { memoizedIsInitialized = 0; return false; } if (!hasHour()) { memoizedIsInitialized = 0; return false; } if (!hasMinute()) { memoizedIsInitialized = 0; return false; } if (!hasSecond()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); if ((bitField0_ & 0x00000001) == 0x00000001) { output.writeUInt32(1, year_); } if ((bitField0_ & 0x00000002) == 0x00000002) { output.writeUInt32(2, month_); } if ((bitField0_ & 0x00000004) == 0x00000004) { output.writeUInt32(4, dayOfMonth_); } if ((bitField0_ & 0x00000008) == 0x00000008) { output.writeEnum(5, dayOfWeek_.getNumber()); } if ((bitField0_ & 0x00000010) == 0x00000010) { output.writeUInt32(6, hour_); } if ((bitField0_ & 0x00000020) == 0x00000020) { output.writeUInt32(7, minute_); } if ((bitField0_ & 0x00000040) == 0x00000040) { output.writeUInt32(8, second_); } getUnknownFields().writeTo(output); } private int memoizedSerializedSize = -1; public int getSerializedSize() { int size = memoizedSerializedSize; if (size != -1) { return size; } size = 0; if ((bitField0_ & 0x00000001) == 0x00000001) { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(1, year_); } if ((bitField0_ & 0x00000002) == 0x00000002) { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(2, month_); } if ((bitField0_ & 0x00000004) == 0x00000004) { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(4, dayOfMonth_); } if ((bitField0_ & 0x00000008) == 0x00000008) { size += com.google.protobuf.CodedOutputStream .computeEnumSize(5, dayOfWeek_.getNumber()); } if ((bitField0_ & 0x00000010) == 0x00000010) { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(6, hour_); } if ((bitField0_ & 0x00000020) == 0x00000020) { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(7, minute_); } if ((bitField0_ & 0x00000040) == 0x00000040) { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(8, second_); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; } private static final long serialVersionUID = 0L; @java.lang.Override protected java.lang.Object writeReplace() throws java.io.ObjectStreamException { return super.writeReplace(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input, extensionRegistry)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder(org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTime_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTime_fieldAccessorTable; } // Construct using org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder(BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { } } private static Builder create() { return new Builder(); } public Builder clear() { super.clear(); year_ = 0; bitField0_ = bitField0_ & ~0x00000001; month_ = 0; bitField0_ = bitField0_ & ~0x00000002; dayOfMonth_ = 0; bitField0_ = bitField0_ & ~0x00000004; dayOfWeek_ = org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek.SUNDAY; bitField0_ = bitField0_ & ~0x00000008; hour_ = 0; bitField0_ = bitField0_ & ~0x00000010; minute_ = 0; bitField0_ = bitField0_ & ~0x00000020; second_ = 0; bitField0_ = bitField0_ & ~0x00000040; return this; } public Builder clone() { return create().mergeFrom(buildPartial()); } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.getDescriptor(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime getDefaultInstanceForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.getDefaultInstance(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime build() { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } private org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); } return result; } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime buildPartial() { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime result = new org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if ((from_bitField0_ & 0x00000001) == 0x00000001) { to_bitField0_ |= 0x00000001; } result.year_ = year_; if ((from_bitField0_ & 0x00000002) == 0x00000002) { to_bitField0_ |= 0x00000002; } result.month_ = month_; if ((from_bitField0_ & 0x00000004) == 0x00000004) { to_bitField0_ |= 0x00000004; } result.dayOfMonth_ = dayOfMonth_; if ((from_bitField0_ & 0x00000008) == 0x00000008) { to_bitField0_ |= 0x00000008; } result.dayOfWeek_ = dayOfWeek_; if ((from_bitField0_ & 0x00000010) == 0x00000010) { to_bitField0_ |= 0x00000010; } result.hour_ = hour_; if ((from_bitField0_ & 0x00000020) == 0x00000020) { to_bitField0_ |= 0x00000020; } result.minute_ = minute_; if ((from_bitField0_ & 0x00000040) == 0x00000040) { to_bitField0_ |= 0x00000040; } result.second_ = second_; result.bitField0_ = to_bitField0_; onBuilt(); return result; } public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime) { return mergeFrom((org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime other) { if (other == org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.getDefaultInstance()) { return this; } if (other.hasYear()) { setYear(other.getYear()); } if (other.hasMonth()) { setMonth(other.getMonth()); } if (other.hasDayOfMonth()) { setDayOfMonth(other.getDayOfMonth()); } if (other.hasDayOfWeek()) { setDayOfWeek(other.getDayOfWeek()); } if (other.hasHour()) { setHour(other.getHour()); } if (other.hasMinute()) { setMinute(other.getMinute()); } if (other.hasSecond()) { setSecond(other.getSecond()); } mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { if (!hasYear()) { return false; } if (!hasMonth()) { return false; } if (!hasDayOfMonth()) { return false; } if (!hasDayOfWeek()) { return false; } if (!hasHour()) { return false; } if (!hasMinute()) { return false; } if (!hasSecond()) { return false; } return true; } public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder( getUnknownFields()); while (true) { int tag = input.readTag(); switch (tag) { case 0: setUnknownFields(unknownFields.build()); onChanged(); return this; default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { setUnknownFields(unknownFields.build()); onChanged(); return this; } break; } case 8: { bitField0_ |= 0x00000001; year_ = input.readUInt32(); break; } case 16: { bitField0_ |= 0x00000002; month_ = input.readUInt32(); break; } case 32: { bitField0_ |= 0x00000004; dayOfMonth_ = input.readUInt32(); break; } case 40: { int rawValue = input.readEnum(); org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek value = org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek.valueOf(rawValue); if (value == null) { unknownFields.mergeVarintField(5, rawValue); } else { bitField0_ |= 0x00000008; dayOfWeek_ = value; } break; } case 48: { bitField0_ |= 0x00000010; hour_ = input.readUInt32(); break; } case 56: { bitField0_ |= 0x00000020; minute_ = input.readUInt32(); break; } case 64: { bitField0_ |= 0x00000040; second_ = input.readUInt32(); break; } } } } private int bitField0_; // required uint32 year = 1; private int year_ ; public boolean hasYear() { return (bitField0_ & 0x00000001) == 0x00000001; } public int getYear() { return year_; } public Builder setYear(int value) { bitField0_ |= 0x00000001; year_ = value; onChanged(); return this; } public Builder clearYear() { bitField0_ = bitField0_ & ~0x00000001; year_ = 0; onChanged(); return this; } // required uint32 month = 2; private int month_ ; public boolean hasMonth() { return (bitField0_ & 0x00000002) == 0x00000002; } public int getMonth() { return month_; } public Builder setMonth(int value) { bitField0_ |= 0x00000002; month_ = value; onChanged(); return this; } public Builder clearMonth() { bitField0_ = bitField0_ & ~0x00000002; month_ = 0; onChanged(); return this; } // required uint32 dayOfMonth = 4; private int dayOfMonth_ ; public boolean hasDayOfMonth() { return (bitField0_ & 0x00000004) == 0x00000004; } public int getDayOfMonth() { return dayOfMonth_; } public Builder setDayOfMonth(int value) { bitField0_ |= 0x00000004; dayOfMonth_ = value; onChanged(); return this; } public Builder clearDayOfMonth() { bitField0_ = bitField0_ & ~0x00000004; dayOfMonth_ = 0; onChanged(); return this; } // required .org.jboss.netty.example.localtime.DayOfWeek dayOfWeek = 5; private org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek dayOfWeek_ = org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek.SUNDAY; public boolean hasDayOfWeek() { return (bitField0_ & 0x00000008) == 0x00000008; } public org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek getDayOfWeek() { return dayOfWeek_; } public Builder setDayOfWeek(org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000008; dayOfWeek_ = value; onChanged(); return this; } public Builder clearDayOfWeek() { bitField0_ = bitField0_ & ~0x00000008; dayOfWeek_ = org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek.SUNDAY; onChanged(); return this; } // required uint32 hour = 6; private int hour_ ; public boolean hasHour() { return (bitField0_ & 0x00000010) == 0x00000010; } public int getHour() { return hour_; } public Builder setHour(int value) { bitField0_ |= 0x00000010; hour_ = value; onChanged(); return this; } public Builder clearHour() { bitField0_ = bitField0_ & ~0x00000010; hour_ = 0; onChanged(); return this; } // required uint32 minute = 7; private int minute_ ; public boolean hasMinute() { return (bitField0_ & 0x00000020) == 0x00000020; } public int getMinute() { return minute_; } public Builder setMinute(int value) { bitField0_ |= 0x00000020; minute_ = value; onChanged(); return this; } public Builder clearMinute() { bitField0_ = bitField0_ & ~0x00000020; minute_ = 0; onChanged(); return this; } // required uint32 second = 8; private int second_ ; public boolean hasSecond() { return (bitField0_ & 0x00000040) == 0x00000040; } public int getSecond() { return second_; } public Builder setSecond(int value) { bitField0_ |= 0x00000040; second_ = value; onChanged(); return this; } public Builder clearSecond() { bitField0_ = bitField0_ & ~0x00000040; second_ = 0; onChanged(); return this; } // @@protoc_insertion_point(builder_scope:org.jboss.netty.example.localtime.LocalTime) } static { defaultInstance = new LocalTime(true); defaultInstance.initFields(); } // @@protoc_insertion_point(class_scope:org.jboss.netty.example.localtime.LocalTime) } public interface LocalTimesOrBuilder extends com.google.protobuf.MessageOrBuilder { // repeated .org.jboss.netty.example.localtime.LocalTime localTime = 1; java.util.List getLocalTimeList(); org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime getLocalTime(int index); int getLocalTimeCount(); java.util.List getLocalTimeOrBuilderList(); org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder getLocalTimeOrBuilder( int index); } public static final class LocalTimes extends com.google.protobuf.GeneratedMessage implements LocalTimesOrBuilder { // Use LocalTimes.newBuilder() to construct. private LocalTimes(Builder builder) { super(builder); } private LocalTimes(boolean noInit) {} private static final LocalTimes defaultInstance; public static LocalTimes getDefaultInstance() { return defaultInstance; } public LocalTimes getDefaultInstanceForType() { return defaultInstance; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTimes_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTimes_fieldAccessorTable; } // repeated .org.jboss.netty.example.localtime.LocalTime localTime = 1; public static final int LOCALTIME_FIELD_NUMBER = 1; private java.util.List localTime_; public java.util.List getLocalTimeList() { return localTime_; } public java.util.List getLocalTimeOrBuilderList() { return localTime_; } public int getLocalTimeCount() { return localTime_.size(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime getLocalTime(int index) { return localTime_.get(index); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder getLocalTimeOrBuilder( int index) { return localTime_.get(index); } private void initFields() { localTime_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) { return isInitialized == 1; } for (int i = 0; i < getLocalTimeCount(); i++) { if (!getLocalTime(i).isInitialized()) { memoizedIsInitialized = 0; return false; } } memoizedIsInitialized = 1; return true; } public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); for (int i = 0; i < localTime_.size(); i++) { output.writeMessage(1, localTime_.get(i)); } getUnknownFields().writeTo(output); } private int memoizedSerializedSize = -1; public int getSerializedSize() { int size = memoizedSerializedSize; if (size != -1) { return size; } size = 0; for (int i = 0; i < localTime_.size(); i++) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(1, localTime_.get(i)); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; } private static final long serialVersionUID = 0L; @java.lang.Override protected java.lang.Object writeReplace() throws java.io.ObjectStreamException { return super.writeReplace(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input, extensionRegistry)) { return builder.buildParsed(); } else { return null; } } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } public static org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder(org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimesOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTimes_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.jboss.netty.example.localtime.LocalTimeProtocol.internal_static_org_jboss_netty_example_localtime_LocalTimes_fieldAccessorTable; } // Construct using org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder(BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { getLocalTimeFieldBuilder(); } } private static Builder create() { return new Builder(); } public Builder clear() { super.clear(); if (localTimeBuilder_ == null) { localTime_ = java.util.Collections.emptyList(); bitField0_ = bitField0_ & ~0x00000001; } else { localTimeBuilder_.clear(); } return this; } public Builder clone() { return create().mergeFrom(buildPartial()); } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes.getDescriptor(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes getDefaultInstanceForType() { return org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes.getDefaultInstance(); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes build() { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } private org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); } return result; } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes buildPartial() { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes result = new org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes(this); int from_bitField0_ = bitField0_; if (localTimeBuilder_ == null) { if ((bitField0_ & 0x00000001) == 0x00000001) { localTime_ = java.util.Collections.unmodifiableList(localTime_); bitField0_ = bitField0_ & ~0x00000001; } result.localTime_ = localTime_; } else { result.localTime_ = localTimeBuilder_.build(); } onBuilt(); return result; } public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes) { return mergeFrom((org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes other) { if (other == org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes.getDefaultInstance()) { return this; } if (localTimeBuilder_ == null) { if (!other.localTime_.isEmpty()) { if (localTime_.isEmpty()) { localTime_ = other.localTime_; bitField0_ = bitField0_ & ~0x00000001; } else { ensureLocalTimeIsMutable(); localTime_.addAll(other.localTime_); } onChanged(); } } else { if (!other.localTime_.isEmpty()) { if (localTimeBuilder_.isEmpty()) { localTimeBuilder_.dispose(); localTimeBuilder_ = null; localTime_ = other.localTime_; bitField0_ = bitField0_ & ~0x00000001; localTimeBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getLocalTimeFieldBuilder() : null; } else { localTimeBuilder_.addAllMessages(other.localTime_); } } } mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { for (int i = 0; i < getLocalTimeCount(); i++) { if (!getLocalTime(i).isInitialized()) { return false; } } return true; } public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder( getUnknownFields()); while (true) { int tag = input.readTag(); switch (tag) { case 0: setUnknownFields(unknownFields.build()); onChanged(); return this; default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { setUnknownFields(unknownFields.build()); onChanged(); return this; } break; } case 10: { org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder subBuilder = org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.newBuilder(); input.readMessage(subBuilder, extensionRegistry); addLocalTime(subBuilder.buildPartial()); break; } } } } private int bitField0_; // repeated .org.jboss.netty.example.localtime.LocalTime localTime = 1; private java.util.List localTime_ = java.util.Collections.emptyList(); private void ensureLocalTimeIsMutable() { if (!((bitField0_ & 0x00000001) == 0x00000001)) { localTime_ = new java.util.ArrayList(localTime_); bitField0_ |= 0x00000001; } } private com.google.protobuf.RepeatedFieldBuilder< org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder> localTimeBuilder_; public java.util.List getLocalTimeList() { if (localTimeBuilder_ == null) { return java.util.Collections.unmodifiableList(localTime_); } else { return localTimeBuilder_.getMessageList(); } } public int getLocalTimeCount() { if (localTimeBuilder_ == null) { return localTime_.size(); } else { return localTimeBuilder_.getCount(); } } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime getLocalTime(int index) { if (localTimeBuilder_ == null) { return localTime_.get(index); } else { return localTimeBuilder_.getMessage(index); } } public Builder setLocalTime( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime value) { if (localTimeBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureLocalTimeIsMutable(); localTime_.set(index, value); onChanged(); } else { localTimeBuilder_.setMessage(index, value); } return this; } public Builder setLocalTime( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder builderForValue) { if (localTimeBuilder_ == null) { ensureLocalTimeIsMutable(); localTime_.set(index, builderForValue.build()); onChanged(); } else { localTimeBuilder_.setMessage(index, builderForValue.build()); } return this; } public Builder addLocalTime(org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime value) { if (localTimeBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureLocalTimeIsMutable(); localTime_.add(value); onChanged(); } else { localTimeBuilder_.addMessage(value); } return this; } public Builder addLocalTime( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime value) { if (localTimeBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureLocalTimeIsMutable(); localTime_.add(index, value); onChanged(); } else { localTimeBuilder_.addMessage(index, value); } return this; } public Builder addLocalTime( org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder builderForValue) { if (localTimeBuilder_ == null) { ensureLocalTimeIsMutable(); localTime_.add(builderForValue.build()); onChanged(); } else { localTimeBuilder_.addMessage(builderForValue.build()); } return this; } public Builder addLocalTime( int index, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder builderForValue) { if (localTimeBuilder_ == null) { ensureLocalTimeIsMutable(); localTime_.add(index, builderForValue.build()); onChanged(); } else { localTimeBuilder_.addMessage(index, builderForValue.build()); } return this; } public Builder addAllLocalTime( java.lang.Iterable values) { if (localTimeBuilder_ == null) { ensureLocalTimeIsMutable(); super.addAll(values, localTime_); onChanged(); } else { localTimeBuilder_.addAllMessages(values); } return this; } public Builder clearLocalTime() { if (localTimeBuilder_ == null) { localTime_ = java.util.Collections.emptyList(); bitField0_ = bitField0_ & ~0x00000001; onChanged(); } else { localTimeBuilder_.clear(); } return this; } public Builder removeLocalTime(int index) { if (localTimeBuilder_ == null) { ensureLocalTimeIsMutable(); localTime_.remove(index); onChanged(); } else { localTimeBuilder_.remove(index); } return this; } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder getLocalTimeBuilder( int index) { return getLocalTimeFieldBuilder().getBuilder(index); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder getLocalTimeOrBuilder( int index) { if (localTimeBuilder_ == null) { return localTime_.get(index); } else { return localTimeBuilder_.getMessageOrBuilder(index); } } public java.util.List getLocalTimeOrBuilderList() { if (localTimeBuilder_ != null) { return localTimeBuilder_.getMessageOrBuilderList(); } else { return java.util.Collections.unmodifiableList(localTime_); } } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder addLocalTimeBuilder() { return getLocalTimeFieldBuilder().addBuilder( org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.getDefaultInstance()); } public org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder addLocalTimeBuilder( int index) { return getLocalTimeFieldBuilder().addBuilder( index, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.getDefaultInstance()); } public java.util.List getLocalTimeBuilderList() { return getLocalTimeFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder> getLocalTimeFieldBuilder() { if (localTimeBuilder_ == null) { localTimeBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimeOrBuilder>( localTime_, (bitField0_ & 0x00000001) == 0x00000001, getParentForChildren(), isClean()); localTime_ = null; } return localTimeBuilder_; } // @@protoc_insertion_point(builder_scope:org.jboss.netty.example.localtime.LocalTimes) } static { defaultInstance = new LocalTimes(true); defaultInstance.initFields(); } // @@protoc_insertion_point(class_scope:org.jboss.netty.example.localtime.LocalTimes) } private static com.google.protobuf.Descriptors.Descriptor internal_static_org_jboss_netty_example_localtime_Location_descriptor; private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_org_jboss_netty_example_localtime_Location_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_org_jboss_netty_example_localtime_Locations_descriptor; private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_org_jboss_netty_example_localtime_Locations_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_org_jboss_netty_example_localtime_LocalTime_descriptor; private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_org_jboss_netty_example_localtime_LocalTime_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_org_jboss_netty_example_localtime_LocalTimes_descriptor; private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_org_jboss_netty_example_localtime_LocalTimes_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } private static com.google.protobuf.Descriptors.FileDescriptor descriptor; static { java.lang.String[] descriptorData = { "\nGsrc/main/java/org/jboss/netty/example/" + "localtime/LocalTimeProtocol.proto\022!org.j" + "boss.netty.example.localtime\"Y\n\010Location" + "\022?\n\tcontinent\030\001 \002(\0162,.org.jboss.netty.ex" + "ample.localtime.Continent\022\014\n\004city\030\002 \002(\t\"" + "J\n\tLocations\022=\n\010location\030\001 \003(\0132+.org.jbo" + "ss.netty.example.localtime.Location\"\253\001\n\t" + "LocalTime\022\014\n\004year\030\001 \002(\r\022\r\n\005month\030\002 \002(\r\022\022" + "\n\ndayOfMonth\030\004 \002(\r\022?\n\tdayOfWeek\030\005 \002(\0162,." + "org.jboss.netty.example.localtime.DayOfW", "eek\022\014\n\004hour\030\006 \002(\r\022\016\n\006minute\030\007 \002(\r\022\016\n\006sec" + "ond\030\010 \002(\r\"M\n\nLocalTimes\022?\n\tlocalTime\030\001 \003" + "(\0132,.org.jboss.netty.example.localtime.L" + "ocalTime*\231\001\n\tContinent\022\n\n\006AFRICA\020\000\022\013\n\007AM" + "ERICA\020\001\022\016\n\nANTARCTICA\020\002\022\n\n\006ARCTIC\020\003\022\010\n\004A" + "SIA\020\004\022\014\n\010ATLANTIC\020\005\022\r\n\tAUSTRALIA\020\006\022\n\n\006EU" + "ROPE\020\007\022\n\n\006INDIAN\020\010\022\013\n\007MIDEAST\020\t\022\013\n\007PACIF" + "IC\020\n*g\n\tDayOfWeek\022\n\n\006SUNDAY\020\001\022\n\n\006MONDAY\020" + "\002\022\013\n\007TUESDAY\020\003\022\r\n\tWEDNESDAY\020\004\022\014\n\010THURSDA" + "Y\020\005\022\n\n\006FRIDAY\020\006\022\014\n\010SATURDAY\020\007B\002H\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.Descriptors.FileDescriptor root) { descriptor = root; internal_static_org_jboss_netty_example_localtime_Location_descriptor = getDescriptor().getMessageTypes().get(0); internal_static_org_jboss_netty_example_localtime_Location_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_jboss_netty_example_localtime_Location_descriptor, new java.lang.String[] { "Continent", "City", }, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.class, org.jboss.netty.example.localtime.LocalTimeProtocol.Location.Builder.class); internal_static_org_jboss_netty_example_localtime_Locations_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_org_jboss_netty_example_localtime_Locations_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_jboss_netty_example_localtime_Locations_descriptor, new java.lang.String[] { "Location", }, org.jboss.netty.example.localtime.LocalTimeProtocol.Locations.class, org.jboss.netty.example.localtime.LocalTimeProtocol.Locations.Builder.class); internal_static_org_jboss_netty_example_localtime_LocalTime_descriptor = getDescriptor().getMessageTypes().get(2); internal_static_org_jboss_netty_example_localtime_LocalTime_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_jboss_netty_example_localtime_LocalTime_descriptor, new java.lang.String[] { "Year", "Month", "DayOfMonth", "DayOfWeek", "Hour", "Minute", "Second", }, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.class, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime.Builder.class); internal_static_org_jboss_netty_example_localtime_LocalTimes_descriptor = getDescriptor().getMessageTypes().get(3); internal_static_org_jboss_netty_example_localtime_LocalTimes_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_jboss_netty_example_localtime_LocalTimes_descriptor, new java.lang.String[] { "LocalTime", }, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes.class, org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes.Builder.class); return null; } }; com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] { }, assigner); } // @@protoc_insertion_point(outer_class_scope) } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/LocalTimeProtocol.proto000066400000000000000000000032531225554127700326660ustar00rootroot00000000000000/* * Copyright 2011 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; // How to generate // =============== // $ protoc src/main/java/org/jboss/netty/example/localtime/LocalTimeProtocol.proto \ // --java_out=src/main/java // // Add @SuppressWarnings("all") to the generated code not to pollute IDE task list. option optimize_for = SPEED; enum Continent { AFRICA = 0; AMERICA = 1; ANTARCTICA = 2; ARCTIC = 3; ASIA = 4; ATLANTIC = 5; AUSTRALIA = 6; EUROPE = 7; INDIAN = 8; MIDEAST = 9; PACIFIC = 10; } message Location { required Continent continent = 1; required string city = 2; } message Locations { repeated Location location = 1; } enum DayOfWeek { SUNDAY = 1; MONDAY = 2; TUESDAY = 3; WEDNESDAY = 4; THURSDAY = 5; FRIDAY = 6; SATURDAY = 7; } message LocalTime { required uint32 year = 1; required uint32 month = 2; required uint32 dayOfMonth = 4; required DayOfWeek dayOfWeek = 5; required uint32 hour = 6; required uint32 minute = 7; required uint32 second = 8; } message LocalTimes { repeated LocalTime localTime = 1; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/LocalTimeServer.java000066400000000000000000000036051225554127700321120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * Receives a list of continent/city pairs from a {@link LocalTimeClient} to * get the local times of the specified cities. */ public class LocalTimeServer { private final int port; public LocalTimeServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new LocalTimeServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new LocalTimeServer(port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/LocalTimeServerHandler.java000066400000000000000000000066761225554127700334230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.example.localtime.LocalTimeProtocol.Continent; import org.jboss.netty.example.localtime.LocalTimeProtocol.DayOfWeek; import org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTime; import org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes; import org.jboss.netty.example.localtime.LocalTimeProtocol.Location; import org.jboss.netty.example.localtime.LocalTimeProtocol.Locations; import java.util.Calendar; import java.util.TimeZone; import java.util.logging.Level; import java.util.logging.Logger; import static java.util.Calendar.*; public class LocalTimeServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( LocalTimeServerHandler.class.getName()); @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { Locations locations = (Locations) e.getMessage(); long currentTime = System.currentTimeMillis(); LocalTimes.Builder builder = LocalTimes.newBuilder(); for (Location l: locations.getLocationList()) { TimeZone tz = TimeZone.getTimeZone( toString(l.getContinent()) + '/' + l.getCity()); Calendar calendar = getInstance(tz); calendar.setTimeInMillis(currentTime); builder.addLocalTime(LocalTime.newBuilder(). setYear(calendar.get(YEAR)). setMonth(calendar.get(MONTH) + 1). setDayOfMonth(calendar.get(DAY_OF_MONTH)). setDayOfWeek(DayOfWeek.valueOf(calendar.get(DAY_OF_WEEK))). setHour(calendar.get(HOUR_OF_DAY)). setMinute(calendar.get(MINUTE)). setSecond(calendar.get(SECOND)).build()); } e.getChannel().write(builder.build()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } private static String toString(Continent c) { return c.name().charAt(0) + c.name().toLowerCase().substring(1); } } LocalTimeServerPipelineFactory.java000066400000000000000000000032551225554127700350520ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/localtime/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.localtime; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; public class LocalTimeServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline p = pipeline(); p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); p.addLast("protobufDecoder", new ProtobufDecoder(LocalTimeProtocol.Locations.getDefaultInstance())); p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender()); p.addLast("protobufEncoder", new ProtobufEncoder()); p.addLast("handler", new LocalTimeServerHandler()); return p; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/objectecho/000077500000000000000000000000001225554127700263375ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoClient.java000066400000000000000000000063521225554127700323540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.objectecho; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.example.echo.EchoClient; import org.jboss.netty.handler.codec.serialization.ClassResolvers; import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder; /** * Modification of {@link EchoClient} which utilizes Java object serialization. */ public class ObjectEchoClient { private final String host; private final int port; private final int firstMessageSize; public ObjectEchoClient(String host, int port, int firstMessageSize) { this.host = host; this.port = port; this.firstMessageSize = firstMessageSize; } public void run() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new ObjectEncoder(), new ObjectDecoder( ClassResolvers.cacheDisabled(getClass().getClassLoader())), new ObjectEchoClientHandler(firstMessageSize)); } }); // Start the connection attempt. bootstrap.connect(new InetSocketAddress(host, port)); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { System.err.println( "Usage: " + ObjectEchoClient.class.getSimpleName() + " []"); return; } // Parse options. final String host = args[0]; final int port = Integer.parseInt(args[1]); final int firstMessageSize; if (args.length == 3) { firstMessageSize = Integer.parseInt(args[2]); } else { firstMessageSize = 256; } new ObjectEchoClient(host, port, firstMessageSize).run(); } } ObjectEchoClientHandler.java000066400000000000000000000064151225554127700335730ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/objectecho/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.objectecho; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handler implementation for the object echo client. It initiates the * ping-pong traffic between the object echo client and server by sending the * first message to the server. */ public class ObjectEchoClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( ObjectEchoClientHandler.class.getName()); private final List firstMessage; private final AtomicLong transferredMessages = new AtomicLong(); /** * Creates a client-side handler. */ public ObjectEchoClientHandler(int firstMessageSize) { if (firstMessageSize <= 0) { throw new IllegalArgumentException( "firstMessageSize: " + firstMessageSize); } firstMessage = new ArrayList(firstMessageSize); for (int i = 0; i < firstMessageSize; i ++) { firstMessage.add(i); } } public long getTransferredMessages() { return transferredMessages.get(); } @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent && ((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) { // Send the first message if this handler is a client-side handler. e.getChannel().write(firstMessage); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Echo back the received object to the server. transferredMessages.incrementAndGet(); e.getChannel().write(e.getMessage()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoServer.java000066400000000000000000000051111225554127700323740ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.objectecho; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.example.echo.EchoServer; import org.jboss.netty.handler.codec.serialization.ClassResolvers; import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder; /** * Modification of {@link EchoServer} which utilizes Java object serialization. */ public class ObjectEchoServer { private final int port; public ObjectEchoServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new ObjectEncoder(), new ObjectDecoder( ClassResolvers.cacheDisabled(getClass().getClassLoader())), new ObjectEchoServerHandler()); } }); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new ObjectEchoServer(port).run(); } } ObjectEchoServerHandler.java000066400000000000000000000046641225554127700336270ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/objectecho/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.objectecho; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handles both client-side and server-side handler depending on which * constructor was called. */ public class ObjectEchoServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( ObjectEchoServerHandler.class.getName()); private final AtomicLong transferredMessages = new AtomicLong(); public long getTransferredMessages() { return transferredMessages.get(); } @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent && ((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Echo back the received object to the client. transferredMessages.incrementAndGet(); e.getChannel().write(e.getMessage()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/portunification/000077500000000000000000000000001225554127700274475ustar00rootroot00000000000000PortUnificationServer.java000066400000000000000000000045461225554127700345500ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/portunification/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.portunification; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * Serves two protocols (HTTP and Factorial) using only one port, enabling * either SSL or GZIP dynamically on demand. *

* Because SSL and GZIP are enabled on demand, 5 combinations per protocol * are possible: none, SSL only, GZIP only, SSL + GZIP, and GZIP + SSL. */ public class PortUnificationServer { private final int port; public PortUnificationServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the event pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new PortUnificationServerHandler()); } }); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new PortUnificationServer(port).run(); } } PortUnificationServerHandler.java000066400000000000000000000132241225554127700360370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/portunification/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.portunification; import javax.net.ssl.SSLEngine; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.example.factorial.BigIntegerDecoder; import org.jboss.netty.example.factorial.FactorialServerHandler; import org.jboss.netty.example.factorial.NumberEncoder; import org.jboss.netty.example.http.snoop.HttpSnoopServerHandler; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.codec.compression.ZlibDecoder; import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibWrapper; import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.ssl.SslHandler; /** * Manipulates the current pipeline dynamically to switch protocols or enable * SSL or GZIP. */ public class PortUnificationServerHandler extends FrameDecoder { private final boolean detectSsl; private final boolean detectGzip; public PortUnificationServerHandler() { this(true, true); } private PortUnificationServerHandler(boolean detectSsl, boolean detectGzip) { this.detectSsl = detectSsl; this.detectGzip = detectGzip; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { // Will use the first 5 bytes to detect a protocol. if (buffer.readableBytes() < 5) { return null; } if (isSsl(buffer)) { enableSsl(ctx); } else { final int magic1 = buffer.getUnsignedByte(buffer.readerIndex()); final int magic2 = buffer.getUnsignedByte(buffer.readerIndex() + 1); if (isGzip(magic1, magic2)) { enableGzip(ctx); } else if (isHttp(magic1, magic2)) { switchToHttp(ctx); } else if (isFactorial(magic1)) { switchToFactorial(ctx); } else { // Unknown protocol; discard everything and close the connection. buffer.skipBytes(buffer.readableBytes()); ctx.getChannel().close(); return null; } } // Forward the current read buffer as is to the new handlers. return buffer.readBytes(buffer.readableBytes()); } private boolean isSsl(ChannelBuffer buffer) { if (detectSsl) { return SslHandler.isEncrypted(buffer); } return false; } private boolean isGzip(int magic1, int magic2) { if (detectGzip) { return magic1 == 31 && magic2 == 139; } return false; } private static boolean isHttp(int magic1, int magic2) { return magic1 == 'G' && magic2 == 'E' || // GET magic1 == 'P' && magic2 == 'O' || // POST magic1 == 'P' && magic2 == 'U' || // PUT magic1 == 'H' && magic2 == 'E' || // HEAD magic1 == 'O' && magic2 == 'P' || // OPTIONS magic1 == 'P' && magic2 == 'A' || // PATCH magic1 == 'D' && magic2 == 'E' || // DELETE magic1 == 'T' && magic2 == 'R' || // TRACE magic1 == 'C' && magic2 == 'O'; // CONNECT } private static boolean isFactorial(int magic1) { return magic1 == 'F'; } private void enableSsl(ChannelHandlerContext ctx) { ChannelPipeline p = ctx.getPipeline(); SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); engine.setUseClientMode(false); p.addLast("ssl", new SslHandler(engine)); p.addLast("unificationA", new PortUnificationServerHandler(false, detectGzip)); p.remove(this); } private void enableGzip(ChannelHandlerContext ctx) { ChannelPipeline p = ctx.getPipeline(); p.addLast("gzipdeflater", new ZlibEncoder(ZlibWrapper.GZIP)); p.addLast("gzipinflater", new ZlibDecoder(ZlibWrapper.GZIP)); p.addLast("unificationB", new PortUnificationServerHandler(detectSsl, false)); p.remove(this); } private void switchToHttp(ChannelHandlerContext ctx) { ChannelPipeline p = ctx.getPipeline(); p.addLast("decoder", new HttpRequestDecoder()); p.addLast("encoder", new HttpResponseEncoder()); p.addLast("deflater", new HttpContentCompressor()); p.addLast("handler", new HttpSnoopServerHandler()); p.remove(this); } private void switchToFactorial(ChannelHandlerContext ctx) { ChannelPipeline p = ctx.getPipeline(); p.addLast("decoder", new BigIntegerDecoder()); p.addLast("encoder", new NumberEncoder()); p.addLast("handler", new FactorialServerHandler()); p.remove(this); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/proxy/000077500000000000000000000000001225554127700254135ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/proxy/HexDumpProxy.java000066400000000000000000000052261225554127700306770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.proxy; import java.net.InetSocketAddress; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class HexDumpProxy { private final int localPort; private final String remoteHost; private final int remotePort; public HexDumpProxy(int localPort, String remoteHost, int remotePort) { this.localPort = localPort; this.remoteHost = remoteHost; this.remotePort = remotePort; } public void run() { System.err.println( "Proxying *:" + localPort + " to " + remoteHost + ':' + remotePort + " ..."); // Configure the bootstrap. Executor executor = Executors.newCachedThreadPool(); ServerBootstrap sb = new ServerBootstrap( new NioServerSocketChannelFactory(executor, executor)); // Set up the event pipeline factory. ClientSocketChannelFactory cf = new NioClientSocketChannelFactory(executor, executor); sb.setPipelineFactory( new HexDumpProxyPipelineFactory(cf, remoteHost, remotePort)); // Start up the server. sb.bind(new InetSocketAddress(localPort)); } public static void main(String[] args) throws Exception { // Validate command line options. if (args.length != 3) { System.err.println( "Usage: " + HexDumpProxy.class.getSimpleName() + " "); return; } // Parse command line options. int localPort = Integer.parseInt(args[0]); String remoteHost = args[1]; int remotePort = Integer.parseInt(args[2]); new HexDumpProxy(localPort, remoteHost, remotePort).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/proxy/HexDumpProxyInboundHandler.java000066400000000000000000000151431225554127700335130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.proxy; import java.net.InetSocketAddress; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler { private final ClientSocketChannelFactory cf; private final String remoteHost; private final int remotePort; // This lock guards against the race condition that overrides the // OP_READ flag incorrectly. // See the related discussion: http://markmail.org/message/x7jc6mqx6ripynqf final Object trafficLock = new Object(); private volatile Channel outboundChannel; public HexDumpProxyInboundHandler( ClientSocketChannelFactory cf, String remoteHost, int remotePort) { this.cf = cf; this.remoteHost = remoteHost; this.remotePort = remotePort; } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Suspend incoming traffic until connected to the remote host. final Channel inboundChannel = e.getChannel(); inboundChannel.setReadable(false); // Start the connection attempt. ClientBootstrap cb = new ClientBootstrap(cf); cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel())); ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort)); outboundChannel = f.getChannel(); f.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { // Connection attempt succeeded: // Begin to accept incoming traffic. inboundChannel.setReadable(true); } else { // Close the connection if the connection attempt has failed. inboundChannel.close(); } } }); } @Override public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception { ChannelBuffer msg = (ChannelBuffer) e.getMessage(); //System.out.println(">>> " + ChannelBuffers.hexDump(msg)); synchronized (trafficLock) { outboundChannel.write(msg); // If outboundChannel is saturated, do not read until notified in // OutboundHandler.channelInterestChanged(). if (!outboundChannel.isWritable()) { e.getChannel().setReadable(false); } } } @Override public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // If inboundChannel is not saturated anymore, continue accepting // the incoming traffic from the outboundChannel. synchronized (trafficLock) { if (e.getChannel().isWritable()) { if (outboundChannel != null) { outboundChannel.setReadable(true); } } } } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (outboundChannel != null) { closeOnFlush(outboundChannel); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); closeOnFlush(e.getChannel()); } private class OutboundHandler extends SimpleChannelUpstreamHandler { private final Channel inboundChannel; OutboundHandler(Channel inboundChannel) { this.inboundChannel = inboundChannel; } @Override public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception { ChannelBuffer msg = (ChannelBuffer) e.getMessage(); //System.out.println("<<< " + ChannelBuffers.hexDump(msg)); synchronized (trafficLock) { inboundChannel.write(msg); // If inboundChannel is saturated, do not read until notified in // HexDumpProxyInboundHandler.channelInterestChanged(). if (!inboundChannel.isWritable()) { e.getChannel().setReadable(false); } } } @Override public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // If outboundChannel is not saturated anymore, continue accepting // the incoming traffic from the inboundChannel. synchronized (trafficLock) { if (e.getChannel().isWritable()) { inboundChannel.setReadable(true); } } } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { closeOnFlush(inboundChannel); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); closeOnFlush(e.getChannel()); } } /** * Closes the specified channel after all queued write requests are flushed. */ static void closeOnFlush(Channel ch) { if (ch.isConnected()) { ch.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/proxy/HexDumpProxyPipelineFactory.java000066400000000000000000000030331225554127700337070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.proxy; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; public class HexDumpProxyPipelineFactory implements ChannelPipelineFactory { private final ClientSocketChannelFactory cf; private final String remoteHost; private final int remotePort; public HexDumpProxyPipelineFactory( ClientSocketChannelFactory cf, String remoteHost, int remotePort) { this.cf = cf; this.remoteHost = remoteHost; this.remotePort = remotePort; } public ChannelPipeline getPipeline() throws Exception { ChannelPipeline p = pipeline(); // Note the static import. p.addLast("handler", new HexDumpProxyInboundHandler(cf, remoteHost, remotePort)); return p; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/qotm/000077500000000000000000000000001225554127700252125ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/qotm/QuoteOfTheMomentClient.java000066400000000000000000000100101225554127700324070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.qotm; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannelFactory; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.util.CharsetUtil; /** * A UDP broadcast client that asks for a quote of the moment (QOTM) to * {@link QuoteOfTheMomentServer}. * * Inspired by the official Java tutorial. */ public class QuoteOfTheMomentClient { private final int port; public QuoteOfTheMomentClient(int port) { this.port = port; } public void run() { DatagramChannelFactory f = new NioDatagramChannelFactory(Executors.newCachedThreadPool()); ConnectionlessBootstrap b = new ConnectionlessBootstrap(f); // Configure the pipeline factory. b.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringEncoder(CharsetUtil.ISO_8859_1), new StringDecoder(CharsetUtil.ISO_8859_1), new QuoteOfTheMomentClientHandler()); } }); // Enable broadcast b.setOption("broadcast", "true"); // Allow packets as large as up to 1024 bytes (default is 768). // You could increase or decrease this value to avoid truncated packets // or to improve memory footprint respectively. // // Please also note that a large UDP packet might be truncated or // dropped by your router no matter how you configured this option. // In UDP, a packet is truncated or dropped if it is larger than a // certain size, depending on router configuration. IPv4 routers // truncate and IPv6 routers drop a large packet. That's why it is // safe to send small packets in UDP. b.setOption( "receiveBufferSizePredictorFactory", new FixedReceiveBufferSizePredictorFactory(1024)); DatagramChannel c = (DatagramChannel) b.bind(new InetSocketAddress(0)); // Broadcast the QOTM request to port 8080. c.write("QOTM?", new InetSocketAddress("255.255.255.255", port)); // QuoteOfTheMomentClientHandler will close the DatagramChannel when a // response is received. If the channel is not closed within 5 seconds, // print an error message and quit. if (!c.getCloseFuture().awaitUninterruptibly(5000)) { System.err.println("QOTM request timed out."); c.close().awaitUninterruptibly(); } f.releaseExternalResources(); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new QuoteOfTheMomentClient(port).run(); } } QuoteOfTheMomentClientHandler.java000066400000000000000000000027361225554127700336460ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/qotm/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.qotm; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String msg = (String) e.getMessage(); if (msg.startsWith("QOTM: ")) { System.out.println("Quote of the Moment: " + msg.substring(6)); e.getChannel().close(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); e.getChannel().close(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/qotm/QuoteOfTheMomentServer.java000066400000000000000000000065601225554127700324560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.qotm; import java.net.InetSocketAddress; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.socket.DatagramChannelFactory; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.util.CharsetUtil; /** * A UDP server that responds to the QOTM (quote of the moment) request to a * {@link QuoteOfTheMomentClient}. * * Inspired by the official Java tutorial. */ public class QuoteOfTheMomentServer { private final int port; public QuoteOfTheMomentServer(int port) { this.port = port; } public void run() { DatagramChannelFactory f = new NioDatagramChannelFactory(); ConnectionlessBootstrap b = new ConnectionlessBootstrap(f); // Configure the pipeline factory. b.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringEncoder(CharsetUtil.ISO_8859_1), new StringDecoder(CharsetUtil.ISO_8859_1), new QuoteOfTheMomentServerHandler()); } }); // Enable broadcast b.setOption("broadcast", "false"); // Allow packets as large as up to 1024 bytes (default is 768). // You could increase or decrease this value to avoid truncated packets // or to improve memory footprint respectively. // // Please also note that a large UDP packet might be truncated or // dropped by your router no matter how you configured this option. // In UDP, a packet is truncated or dropped if it is larger than a // certain size, depending on router configuration. IPv4 routers // truncate and IPv6 routers drop a large packet. That's why it is // safe to send small packets in UDP. b.setOption( "receiveBufferSizePredictorFactory", new FixedReceiveBufferSizePredictorFactory(1024)); // Bind to the port and start the service. b.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new QuoteOfTheMomentServer(port).run(); } } QuoteOfTheMomentServerHandler.java000066400000000000000000000041531225554127700336710ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/qotm/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.qotm; import java.util.Random; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler { private static final Random random = new Random(); // Quotes from Mohandas K. Gandhi: private static final String[] quotes = { "Where there is love there is life.", "First they ignore you, then they laugh at you, then they fight you, then you win.", "Be the change you want to see in the world.", "The weak can never forgive. Forgiveness is the attribute of the strong.", }; private static String nextQuote() { int quoteId; synchronized (random) { quoteId = random.nextInt(quotes.length); } return quotes[quoteId]; } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String msg = (String) e.getMessage(); if ("QOTM?".equals(msg)) { e.getChannel().write("QOTM: " + nextQuote(), e.getRemoteAddress()); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); // We don't close the channel because we can keep serving requests. } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/000077500000000000000000000000001225554127700263605ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/SecureChatClient.java000066400000000000000000000074251225554127700324200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.example.telnet.TelnetClient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.util.concurrent.Executors; /** * Simple SSL chat client modified from {@link TelnetClient}. */ public class SecureChatClient { private final String host; private final int port; public SecureChatClient(String host, int port) { this.host = host; this.port = port; } public void run() throws IOException { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Configure the pipeline factory. bootstrap.setPipelineFactory(new SecureChatClientPipelineFactory()); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. Channel channel = future.awaitUninterruptibly().getChannel(); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return; } // Read commands from the stdin. ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (;;) { String line = in.readLine(); if (line == null) { break; } // Sends the received line to the server. lastWriteFuture = channel.write(line + "\r\n"); // If user typed the 'bye' command, wait until the server closes // the connection. if ("bye".equals(line.toLowerCase())) { channel.getCloseFuture().awaitUninterruptibly(); break; } } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.awaitUninterruptibly(); } // Close the connection. Make sure the close operation ends because // all I/O operations are asynchronous in Netty. channel.close().awaitUninterruptibly(); // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length != 2) { System.err.println( "Usage: " + SecureChatClient.class.getSimpleName() + " "); return; } // Parse options. String host = args[0]; int port = Integer.parseInt(args[1]); new SecureChatClient(host, port).run(); } } SecureChatClientHandler.java000066400000000000000000000045431225554127700336350ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.ssl.SslHandler; /** * Handles a client-side channel. */ public class SecureChatClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( SecureChatClientHandler.class.getName()); @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Get the SslHandler from the pipeline // which were added in SecureChatPipelineFactory. SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); // Begin handshake. sslHandler.handshake(); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { System.err.println(e.getMessage()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } SecureChatClientPipelineFactory.java000066400000000000000000000045361225554127700353570ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import static org.jboss.netty.channel.Channels.*; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.ssl.SslHandler; /** * Creates a newly configured {@link ChannelPipeline} for a new channel. */ public class SecureChatClientPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); // Add SSL handler first to encrypt and decrypt everything. // In this example, we use a bogus certificate in the server side // and accept any invalid certificates in the client side. // You will need something more complicated to identify both // and server in the real world. SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine(); engine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(engine)); // On top of the SSL handler, add the text line codec. pipeline.addLast("framer", new DelimiterBasedFrameDecoder( 8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); // and then business logic. pipeline.addLast("handler", new SecureChatClientHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/SecureChatKeyStore.java000066400000000000000000000374041225554127700327470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import java.io.ByteArrayInputStream; import java.io.InputStream; /** * A bogus key store which provides all the required information to * create an example SSL connection. * * To generate a bogus key store: *

 * keytool  -genkey -alias securechat -keysize 2048 -validity 36500
 *          -keyalg RSA -dname "CN=securechat"
 *          -keypass secret -storepass secret
 *          -keystore cert.jks
 * 
*/ public final class SecureChatKeyStore { private static final short[] DATA = { 0xfe, 0xed, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00, 0x00, 0x01, 0x1a, 0x9f, 0x57, 0xa5, 0x27, 0x00, 0x00, 0x01, 0x9a, 0x30, 0x82, 0x01, 0x96, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x2a, 0x02, 0x11, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x82, 0x48, 0x6d, 0xcf, 0x16, 0xb5, 0x50, 0x95, 0x36, 0xbf, 0x47, 0x27, 0x50, 0x58, 0x0d, 0xa2, 0x52, 0x7e, 0x25, 0xab, 0x14, 0x1a, 0x26, 0x5e, 0x2d, 0x8a, 0x23, 0x90, 0x60, 0x7f, 0x12, 0x20, 0x56, 0xd1, 0x43, 0xa2, 0x6b, 0x47, 0x5d, 0xed, 0x9d, 0xd4, 0xe5, 0x83, 0x28, 0x89, 0xc2, 0x16, 0x4c, 0x76, 0x06, 0xad, 0x8e, 0x8c, 0x29, 0x1a, 0x9b, 0x0f, 0xdd, 0x60, 0x4b, 0xb4, 0x62, 0x82, 0x9e, 0x4a, 0x63, 0x83, 0x2e, 0xd2, 0x43, 0x78, 0xc2, 0x32, 0x1f, 0x60, 0xa9, 0x8a, 0x7f, 0x0f, 0x7c, 0xa6, 0x1d, 0xe6, 0x92, 0x9e, 0x52, 0xc7, 0x7d, 0xbb, 0x35, 0x3b, 0xaa, 0x89, 0x73, 0x4c, 0xfb, 0x99, 0x54, 0x97, 0x99, 0x28, 0x6e, 0x66, 0x5b, 0xf7, 0x9b, 0x7e, 0x6d, 0x8a, 0x2f, 0xfa, 0xc3, 0x1e, 0x71, 0xb9, 0xbd, 0x8f, 0xc5, 0x63, 0x25, 0x31, 0x20, 0x02, 0xff, 0x02, 0xf0, 0xc9, 0x2c, 0xdd, 0x3a, 0x10, 0x30, 0xab, 0xe5, 0xad, 0x3d, 0x1a, 0x82, 0x77, 0x46, 0xed, 0x03, 0x38, 0xa4, 0x73, 0x6d, 0x36, 0x36, 0x33, 0x70, 0xb2, 0x63, 0x20, 0xca, 0x03, 0xbf, 0x5a, 0xf4, 0x7c, 0x35, 0xf0, 0x63, 0x1a, 0x12, 0x33, 0x12, 0x58, 0xd9, 0xa2, 0x63, 0x6b, 0x63, 0x82, 0x41, 0x65, 0x70, 0x37, 0x4b, 0x99, 0x04, 0x9f, 0xdd, 0x5e, 0x07, 0x01, 0x95, 0x9f, 0x36, 0xe8, 0xc3, 0x66, 0x2a, 0x21, 0x69, 0x68, 0x40, 0xe6, 0xbc, 0xbb, 0x85, 0x81, 0x21, 0x13, 0xe6, 0xa4, 0xcf, 0xd3, 0x67, 0xe3, 0xfd, 0x75, 0xf0, 0xdf, 0x83, 0xe0, 0xc5, 0x36, 0x09, 0xac, 0x1b, 0xd4, 0xf7, 0x2a, 0x23, 0x57, 0x1c, 0x5c, 0x0f, 0xf4, 0xcf, 0xa2, 0xcf, 0xf5, 0xbd, 0x9c, 0x69, 0x98, 0x78, 0x3a, 0x25, 0xe4, 0xfd, 0x85, 0x11, 0xcc, 0x7d, 0xef, 0xeb, 0x74, 0x60, 0xb1, 0xb7, 0xfb, 0x1f, 0x0e, 0x62, 0xff, 0xfe, 0x09, 0x0a, 0xc3, 0x80, 0x2f, 0x10, 0x49, 0x89, 0x78, 0xd2, 0x08, 0xfa, 0x89, 0x22, 0x45, 0x91, 0x21, 0xbc, 0x90, 0x3e, 0xad, 0xb3, 0x0a, 0xb4, 0x0e, 0x1c, 0xa1, 0x93, 0x92, 0xd8, 0x72, 0x07, 0x54, 0x60, 0xe7, 0x91, 0xfc, 0xd9, 0x3c, 0xe1, 0x6f, 0x08, 0xe4, 0x56, 0xf6, 0x0b, 0xb0, 0x3c, 0x39, 0x8a, 0x2d, 0x48, 0x44, 0x28, 0x13, 0xca, 0xe9, 0xf7, 0xa3, 0xb6, 0x8a, 0x5f, 0x31, 0xa9, 0x72, 0xf2, 0xde, 0x96, 0xf2, 0xb1, 0x53, 0xb1, 0x3e, 0x24, 0x57, 0xfd, 0x18, 0x45, 0x1f, 0xc5, 0x33, 0x1b, 0xa4, 0xe8, 0x21, 0xfa, 0x0e, 0xb2, 0xb9, 0xcb, 0xc7, 0x07, 0x41, 0xdd, 0x2f, 0xb6, 0x6a, 0x23, 0x18, 0xed, 0xc1, 0xef, 0xe2, 0x4b, 0xec, 0xc9, 0xba, 0xfb, 0x46, 0x43, 0x90, 0xd7, 0xb5, 0x68, 0x28, 0x31, 0x2b, 0x8d, 0xa8, 0x51, 0x63, 0xf7, 0x53, 0x99, 0x19, 0x68, 0x85, 0x66, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x58, 0x2e, 0x35, 0x30, 0x39, 0x00, 0x00, 0x02, 0x3a, 0x30, 0x82, 0x02, 0x36, 0x30, 0x82, 0x01, 0xe0, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x59, 0xf1, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xa0, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4b, 0x79, 0x75, 0x6e, 0x67, 0x67, 0x69, 0x2d, 0x64, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0b, 0x53, 0x65, 0x6f, 0x6e, 0x67, 0x6e, 0x61, 0x6d, 0x2d, 0x73, 0x69, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x74, 0x79, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0f, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, 0x61, 0x6d, 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x36, 0x31, 0x39, 0x30, 0x35, 0x34, 0x31, 0x33, 0x38, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x38, 0x37, 0x31, 0x31, 0x32, 0x34, 0x30, 0x35, 0x34, 0x31, 0x33, 0x38, 0x5a, 0x30, 0x81, 0xa0, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4b, 0x79, 0x75, 0x6e, 0x67, 0x67, 0x69, 0x2d, 0x64, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0b, 0x53, 0x65, 0x6f, 0x6e, 0x67, 0x6e, 0x61, 0x6d, 0x2d, 0x73, 0x69, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x74, 0x79, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0f, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, 0x61, 0x6d, 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xc3, 0xe3, 0x5e, 0x41, 0xa7, 0x87, 0x11, 0x00, 0x42, 0x2a, 0xb0, 0x4b, 0xed, 0xb2, 0xe0, 0x23, 0xdb, 0xb1, 0x3d, 0x58, 0x97, 0x35, 0x60, 0x0b, 0x82, 0x59, 0xd3, 0x00, 0xea, 0xd4, 0x61, 0xb8, 0x79, 0x3f, 0xb6, 0x3c, 0x12, 0x05, 0x93, 0x2e, 0x9a, 0x59, 0x68, 0x14, 0x77, 0x3a, 0xc8, 0x50, 0x25, 0x57, 0xa4, 0x49, 0x18, 0x63, 0x41, 0xf0, 0x2d, 0x28, 0xec, 0x06, 0xfb, 0xb4, 0x9f, 0xbf, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x65, 0x6c, 0x30, 0x01, 0xc2, 0x8e, 0x3e, 0xcb, 0xb3, 0x77, 0x48, 0xe9, 0x66, 0x61, 0x9a, 0x40, 0x86, 0xaf, 0xf6, 0x03, 0xeb, 0xba, 0x6a, 0xf2, 0xfd, 0xe2, 0xaf, 0x36, 0x5e, 0x7b, 0xaa, 0x22, 0x04, 0xdd, 0x2c, 0x20, 0xc4, 0xfc, 0xdd, 0xd0, 0x82, 0x20, 0x1c, 0x3d, 0xd7, 0x9e, 0x5e, 0x5c, 0x92, 0x5a, 0x76, 0x71, 0x28, 0xf5, 0x07, 0x7d, 0xa2, 0x81, 0xba, 0x77, 0x9f, 0x2a, 0xd9, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x6d, 0x79, 0x6b, 0x65, 0x79, 0x00, 0x00, 0x01, 0x1a, 0x9f, 0x5b, 0x56, 0xa0, 0x00, 0x00, 0x01, 0x99, 0x30, 0x82, 0x01, 0x95, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x2a, 0x02, 0x11, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x81, 0x29, 0xa8, 0xb6, 0x08, 0x0c, 0x85, 0x75, 0x3e, 0xdd, 0xb5, 0xe5, 0x1a, 0x87, 0x68, 0xd1, 0x90, 0x4b, 0x29, 0x31, 0xee, 0x90, 0xbc, 0x9d, 0x73, 0xa0, 0x3f, 0xe9, 0x0b, 0xa4, 0xef, 0x30, 0x9b, 0x36, 0x9a, 0xb2, 0x54, 0x77, 0x81, 0x07, 0x4b, 0xaa, 0xa5, 0x77, 0x98, 0xe1, 0xeb, 0xb5, 0x7c, 0x4e, 0x48, 0xd5, 0x08, 0xfc, 0x2c, 0x36, 0xe2, 0x65, 0x03, 0xac, 0xe5, 0xf3, 0x96, 0xb7, 0xd0, 0xb5, 0x3b, 0x92, 0xe4, 0x14, 0x05, 0x7a, 0x6a, 0x92, 0x56, 0xfe, 0x4e, 0xab, 0xd3, 0x0e, 0x32, 0x04, 0x22, 0x22, 0x74, 0x47, 0x7d, 0xec, 0x21, 0x99, 0x30, 0x31, 0x64, 0x46, 0x64, 0x9b, 0xc7, 0x13, 0xbf, 0xbe, 0xd0, 0x31, 0x49, 0xe7, 0x3c, 0xbf, 0xba, 0xb1, 0x20, 0xf9, 0x42, 0xf4, 0xa9, 0xa9, 0xe5, 0x13, 0x65, 0x32, 0xbf, 0x7c, 0xcc, 0x91, 0xd3, 0xfd, 0x24, 0x47, 0x0b, 0xe5, 0x53, 0xad, 0x50, 0x30, 0x56, 0xd1, 0xfa, 0x9c, 0x37, 0xa8, 0xc1, 0xce, 0xf6, 0x0b, 0x18, 0xaa, 0x7c, 0xab, 0xbd, 0x1f, 0xdf, 0xe4, 0x80, 0xb8, 0xa7, 0xe0, 0xad, 0x7d, 0x50, 0x74, 0xf1, 0x98, 0x78, 0xbc, 0x58, 0xb9, 0xc2, 0x52, 0xbe, 0xd2, 0x5b, 0x81, 0x94, 0x83, 0x8f, 0xb9, 0x4c, 0xee, 0x01, 0x2b, 0x5e, 0xc9, 0x6e, 0x9b, 0xf5, 0x63, 0x69, 0xe4, 0xd8, 0x0b, 0x47, 0xd8, 0xfd, 0xd8, 0xe0, 0xed, 0xa8, 0x27, 0x03, 0x74, 0x1e, 0x5d, 0x32, 0xe6, 0x5c, 0x63, 0xc2, 0xfb, 0x3f, 0xee, 0xb4, 0x13, 0xc6, 0x0e, 0x6e, 0x74, 0xe0, 0x22, 0xac, 0xce, 0x79, 0xf9, 0x43, 0x68, 0xc1, 0x03, 0x74, 0x2b, 0xe1, 0x18, 0xf8, 0x7f, 0x76, 0x9a, 0xea, 0x82, 0x3f, 0xc2, 0xa6, 0xa7, 0x4c, 0xfe, 0xae, 0x29, 0x3b, 0xc1, 0x10, 0x7c, 0xd5, 0x77, 0x17, 0x79, 0x5f, 0xcb, 0xad, 0x1f, 0xd8, 0xa1, 0xfd, 0x90, 0xe1, 0x6b, 0xb2, 0xef, 0xb9, 0x41, 0x26, 0xa4, 0x0b, 0x4f, 0xc6, 0x83, 0x05, 0x6f, 0xf0, 0x64, 0x40, 0xe1, 0x44, 0xc4, 0xf9, 0x40, 0x2b, 0x3b, 0x40, 0xdb, 0xaf, 0x35, 0xa4, 0x9b, 0x9f, 0xc4, 0x74, 0x07, 0xe5, 0x18, 0x60, 0xc5, 0xfe, 0x15, 0x0e, 0x3a, 0x25, 0x2a, 0x11, 0xee, 0x78, 0x2f, 0xb8, 0xd1, 0x6e, 0x4e, 0x3c, 0x0a, 0xb5, 0xb9, 0x40, 0x86, 0x27, 0x6d, 0x8f, 0x53, 0xb7, 0x77, 0x36, 0xec, 0x5d, 0xed, 0x32, 0x40, 0x43, 0x82, 0xc3, 0x52, 0x58, 0xc4, 0x26, 0x39, 0xf3, 0xb3, 0xad, 0x58, 0xab, 0xb7, 0xf7, 0x8e, 0x0e, 0xba, 0x8e, 0x78, 0x9d, 0xbf, 0x58, 0x34, 0xbd, 0x77, 0x73, 0xa6, 0x50, 0x55, 0x00, 0x60, 0x26, 0xbf, 0x6d, 0xb4, 0x98, 0x8a, 0x18, 0x83, 0x89, 0xf8, 0xcd, 0x0d, 0x49, 0x06, 0xae, 0x51, 0x6e, 0xaf, 0xbd, 0xe2, 0x07, 0x13, 0xd8, 0x64, 0xcc, 0xbf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x58, 0x2e, 0x35, 0x30, 0x39, 0x00, 0x00, 0x02, 0x34, 0x30, 0x82, 0x02, 0x30, 0x30, 0x82, 0x01, 0xda, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x59, 0xf2, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x9d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4b, 0x79, 0x75, 0x6e, 0x67, 0x67, 0x69, 0x2d, 0x64, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0b, 0x53, 0x65, 0x6f, 0x6e, 0x67, 0x6e, 0x61, 0x6d, 0x2d, 0x73, 0x69, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x74, 0x79, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x73, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, 0x61, 0x6d, 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x36, 0x31, 0x39, 0x30, 0x35, 0x34, 0x35, 0x34, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x38, 0x37, 0x31, 0x31, 0x32, 0x33, 0x30, 0x35, 0x34, 0x35, 0x34, 0x30, 0x5a, 0x30, 0x81, 0x9d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4b, 0x79, 0x75, 0x6e, 0x67, 0x67, 0x69, 0x2d, 0x64, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0b, 0x53, 0x65, 0x6f, 0x6e, 0x67, 0x6e, 0x61, 0x6d, 0x2d, 0x73, 0x69, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x74, 0x79, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x73, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, 0x61, 0x6d, 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x95, 0xb3, 0x47, 0x17, 0x95, 0x0f, 0x57, 0xcf, 0x66, 0x72, 0x0a, 0x7e, 0x5b, 0x54, 0xea, 0x8c, 0x6f, 0x79, 0xde, 0x94, 0xac, 0x0b, 0x5a, 0xd4, 0xd6, 0x1b, 0x58, 0x12, 0x1a, 0x16, 0x3d, 0xfe, 0xdf, 0xa5, 0x2b, 0x86, 0xbc, 0x64, 0xd4, 0x80, 0x1e, 0x3f, 0xf9, 0xe2, 0x04, 0x03, 0x79, 0x9b, 0xc1, 0x5c, 0xf0, 0xf1, 0xf3, 0xf1, 0xe3, 0xbf, 0x3f, 0xc0, 0x1f, 0xdd, 0xdb, 0xc0, 0x5b, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x02, 0xd7, 0xdd, 0xbd, 0x0c, 0x8e, 0x21, 0x20, 0xef, 0x9e, 0x4f, 0x1f, 0xf5, 0x49, 0xf1, 0xae, 0x58, 0x9b, 0x94, 0x3a, 0x1f, 0x70, 0x33, 0xf0, 0x9b, 0xbb, 0xe9, 0xc0, 0xf3, 0x72, 0xcb, 0xde, 0xb6, 0x56, 0x72, 0xcc, 0x1c, 0xf0, 0xd6, 0x5a, 0x2a, 0xbc, 0xa1, 0x7e, 0x23, 0x83, 0xe9, 0xe7, 0xcf, 0x9e, 0xa5, 0xf9, 0xcc, 0xc2, 0x61, 0xf4, 0xdb, 0x40, 0x93, 0x1d, 0x63, 0x8a, 0x50, 0x4c, 0x11, 0x39, 0xb1, 0x91, 0xc1, 0xe6, 0x9d, 0xd9, 0x1a, 0x62, 0x1b, 0xb8, 0xd3, 0xd6, 0x9a, 0x6d, 0xb9, 0x8e, 0x15, 0x51 }; public static InputStream asInputStream() { byte[] data = new byte[DATA.length]; for (int i = 0; i < data.length; i ++) { data[i] = (byte) DATA[i]; } return new ByteArrayInputStream(data); } public static char[] getCertificatePassword() { return "secret".toCharArray(); } public static char[] getKeyStorePassword() { return "secret".toCharArray(); } private SecureChatKeyStore() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/SecureChatServer.java000066400000000000000000000035741225554127700324510ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.example.telnet.TelnetServer; /** * Simple SSL chat server modified from {@link TelnetServer}. */ public class SecureChatServer { private final int port; public SecureChatServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Configure the pipeline factory. bootstrap.setPipelineFactory(new SecureChatServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8443; } new SecureChatServer(port).run(); } } SecureChatServerHandler.java000066400000000000000000000113321225554127700336570ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.group.DefaultChannelGroup; import org.jboss.netty.handler.ssl.SslHandler; import java.net.InetAddress; import java.util.logging.Level; import java.util.logging.Logger; /** * Handles a server-side channel. */ public class SecureChatServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( SecureChatServerHandler.class.getName()); static final ChannelGroup channels = new DefaultChannelGroup(); @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Get the SslHandler in the current pipeline. // We added it in SecureChatPipelineFactory. final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); // Get notified when SSL handshake is done. ChannelFuture handshakeFuture = sslHandler.handshake(); handshakeFuture.addListener(new Greeter(sslHandler)); } @Override public void channelDisconnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Unregister the channel from the global channel list // so the channel does not receive messages anymore. channels.remove(e.getChannel()); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Convert to a String first. String request = (String) e.getMessage(); // Send the received message to all channels but the current one. for (Channel c: channels) { if (c != e.getChannel()) { c.write("[" + e.getChannel().getRemoteAddress() + "] " + request + '\n'); } else { c.write("[you] " + request + '\n'); } } // Close the connection if the client has sent 'bye'. if ("bye".equals(request.toLowerCase())) { e.getChannel().close(); } } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } private static final class Greeter implements ChannelFutureListener { private final SslHandler sslHandler; Greeter(SslHandler sslHandler) { this.sslHandler = sslHandler; } public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { // Once session is secured, send a greeting. future.getChannel().write( "Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n"); future.getChannel().write( "Your session is protected by " + sslHandler.getEngine().getSession().getCipherSuite() + " cipher suite.\n"); // Register the channel to the global channel list // so the channel received the messages from others. channels.add(future.getChannel()); } else { future.getChannel().close(); } } } } SecureChatServerPipelineFactory.java000066400000000000000000000047201225554127700354020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import static org.jboss.netty.channel.Channels.*; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.ssl.SslHandler; /** * Creates a newly configured {@link ChannelPipeline} for a new channel. */ public class SecureChatServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); // Add SSL handler first to encrypt and decrypt everything. // In this example, we use a bogus certificate in the server side // and accept any invalid certificates in the client side. // You will need something more complicated to identify both // and server in the real world. // // Read SecureChatSslContextFactory // if you need client certificate authentication. SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); engine.setUseClientMode(false); pipeline.addLast("ssl", new SslHandler(engine)); // On top of the SSL handler, add the text line codec. pipeline.addLast("framer", new DelimiterBasedFrameDecoder( 8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); // and then business logic. pipeline.addLast("handler", new SecureChatServerHandler()); return pipeline; } } SecureChatSslContextFactory.java000066400000000000000000000076241225554127700345620ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import org.jboss.netty.handler.ssl.SslHandler; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import java.security.KeyStore; import java.security.SecureRandom; import java.security.Security; /** * Creates a bogus {@link SSLContext}. A client-side context created by this * factory accepts any certificate even if it is invalid. A server-side context * created by this factory sends a bogus certificate defined in {@link SecureChatKeyStore}. *

* You will have to create your context differently in a real world application. * *

Client Certificate Authentication

* * To enable client certificate authentication: *
    *
  • Enable client authentication on the server side by calling * {@link SSLEngine#setNeedClientAuth(boolean)} before creating * {@link SslHandler}.
  • *
  • When initializing an {@link SSLContext} on the client side, * specify the {@link KeyManager} that contains the client certificate as * the first argument of {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}.
  • *
  • When initializing an {@link SSLContext} on the server side, * specify the proper {@link TrustManager} as the second argument of * {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)} * to validate the client certificate.
  • *
*/ public final class SecureChatSslContextFactory { private static final String PROTOCOL = "TLS"; private static final SSLContext SERVER_CONTEXT; private static final SSLContext CLIENT_CONTEXT; static { String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); if (algorithm == null) { algorithm = "SunX509"; } SSLContext serverContext; SSLContext clientContext; try { KeyStore ks = KeyStore.getInstance("JKS"); ks.load(SecureChatKeyStore.asInputStream(), SecureChatKeyStore.getKeyStorePassword()); // Set up key manager factory to use our key store KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); kmf.init(ks, SecureChatKeyStore.getCertificatePassword()); // Initialize the SSLContext to work with our key managers. serverContext = SSLContext.getInstance(PROTOCOL); serverContext.init(kmf.getKeyManagers(), null, null); } catch (Exception e) { throw new Error( "Failed to initialize the server-side SSLContext", e); } try { clientContext = SSLContext.getInstance(PROTOCOL); clientContext.init(null, SecureChatTrustManagerFactory.getTrustManagers(), null); } catch (Exception e) { throw new Error( "Failed to initialize the client-side SSLContext", e); } SERVER_CONTEXT = serverContext; CLIENT_CONTEXT = clientContext; } public static SSLContext getServerContext() { return SERVER_CONTEXT; } public static SSLContext getClientContext() { return CLIENT_CONTEXT; } private SecureChatSslContextFactory() { // Unused } } SecureChatTrustManagerFactory.java000066400000000000000000000051771225554127700350710ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/securechat/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.securechat; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactorySpi; import javax.net.ssl.X509TrustManager; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.X509Certificate; /** * Bogus {@link TrustManagerFactorySpi} which accepts any certificate * even if it is invalid. */ public class SecureChatTrustManagerFactory extends TrustManagerFactorySpi { private static final TrustManager DUMMY_TRUST_MANAGER = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] chain, String authType) { // Always trust - it is an example. // You should do something in the real world. // You will reach here only if you enabled client certificate auth, // as described in SecureChatSslContextFactory. System.err.println( "UNKNOWN CLIENT CERTIFICATE: " + chain[0].getSubjectDN()); } public void checkServerTrusted(X509Certificate[] chain, String authType) { // Always trust - it is an example. // You should do something in the real world. System.err.println( "UNKNOWN SERVER CERTIFICATE: " + chain[0].getSubjectDN()); } }; public static TrustManager[] getTrustManagers() { return new TrustManager[] { DUMMY_TRUST_MANAGER }; } @Override protected TrustManager[] engineGetTrustManagers() { return getTrustManagers(); } @Override protected void engineInit(KeyStore keystore) throws KeyStoreException { // Unused } @Override protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws InvalidAlgorithmParameterException { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/000077500000000000000000000000001225554127700255255ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/TelnetClient.java000066400000000000000000000072501225554127700307660ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.telnet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; /** * Simplistic telnet client. */ public class TelnetClient { private final String host; private final int port; public TelnetClient(String host, int port) { this.host = host; this.port = port; } public void run() throws IOException { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Configure the pipeline factory. bootstrap.setPipelineFactory(new TelnetClientPipelineFactory()); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. Channel channel = future.awaitUninterruptibly().getChannel(); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return; } // Read commands from the stdin. ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (;;) { String line = in.readLine(); if (line == null) { break; } // Sends the received line to the server. lastWriteFuture = channel.write(line + "\r\n"); // If user typed the 'bye' command, wait until the server closes // the connection. if ("bye".equals(line.toLowerCase())) { channel.getCloseFuture().awaitUninterruptibly(); break; } } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.awaitUninterruptibly(); } // Close the connection. Make sure the close operation ends because // all I/O operations are asynchronous in Netty. channel.close().awaitUninterruptibly(); // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length != 2) { System.err.println( "Usage: " + TelnetClient.class.getSimpleName() + " "); return; } // Parse options. String host = args[0]; int port = Integer.parseInt(args[1]); new TelnetClient(host, port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/TelnetClientHandler.java000066400000000000000000000037521225554127700322670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.telnet; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handles a client-side channel. */ public class TelnetClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( TelnetClientHandler.class.getName()); @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Print out the line received from the server. System.err.println(e.getMessage()); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } TelnetClientPipelineFactory.java000066400000000000000000000034431225554127700337250ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.telnet; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; /** * Creates a newly configured {@link ChannelPipeline} for a new channel. */ public class TelnetClientPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Add the text line codec combination first, pipeline.addLast("framer", new DelimiterBasedFrameDecoder( 8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); // and then business logic. pipeline.addLast("handler", new TelnetClientHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/TelnetServer.java000066400000000000000000000034231225554127700310140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.telnet; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * Simplistic telnet server. */ public class TelnetServer { private final int port; public TelnetServer(int port) { this.port = port; } public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Configure the pipeline factory. bootstrap.setPipelineFactory(new TelnetServerPipelineFactory()); // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(port)); } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new TelnetServer(port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/TelnetServerHandler.java000066400000000000000000000065461225554127700323230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.telnet; import java.net.InetAddress; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * Handles a server-side channel. */ public class TelnetServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( TelnetServerHandler.class.getName()); @Override public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } super.handleUpstream(ctx, e); } @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Send greeting for a new connection. e.getChannel().write( "Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n"); e.getChannel().write("It is " + new Date() + " now.\r\n"); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { // Cast to a String first. // We know it is a String because we put some codec in TelnetPipelineFactory. String request = (String) e.getMessage(); // Generate and write a response. String response; boolean close = false; if (request.length() == 0) { response = "Please type something.\r\n"; } else if ("bye".equals(request.toLowerCase())) { response = "Have a good day!\r\n"; close = true; } else { response = "Did you say '" + request + "'?\r\n"; } // We do not need to write a ChannelBuffer here. // We know the encoder inserted at TelnetPipelineFactory will do the conversion. ChannelFuture future = e.getChannel().write(response); // Close the connection after sending 'Have a good day!' // if the client has sent 'bye'. if (close) { future.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { logger.log( Level.WARNING, "Unexpected exception from downstream.", e.getCause()); e.getChannel().close(); } } TelnetServerPipelineFactory.java000066400000000000000000000034431225554127700337550ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/telnet/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.telnet; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; /** * Creates a newly configured {@link ChannelPipeline} for a new channel. */ public class TelnetServerPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); // Add the text line codec combination first, pipeline.addLast("framer", new DelimiterBasedFrameDecoder( 8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); // and then business logic. pipeline.addLast("handler", new TelnetServerHandler()); return pipeline; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/uptime/000077500000000000000000000000001225554127700255355ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/uptime/UptimeClient.java000066400000000000000000000066221225554127700310100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.uptime; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.timeout.ReadTimeoutHandler; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timer; /** * Connects to a server periodically to measure and print the uptime of the * server. This example demonstrates how to implement reliable reconnection * mechanism in Netty. */ public class UptimeClient { // Sleep 5 seconds before a reconnection attempt. static final int RECONNECT_DELAY = 5; // Reconnect when the server sends nothing for 10 seconds. private static final int READ_TIMEOUT = 10; private final String host; private final int port; public UptimeClient(String host, int port) { this.host = host; this.port = port; } public void run() { // Initialize the timer that schedules subsequent reconnection attempts. final Timer timer = new HashedWheelTimer(); // Configure the client. final ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Configure the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { private final ChannelHandler timeoutHandler = new ReadTimeoutHandler(timer, READ_TIMEOUT); private final ChannelHandler uptimeHandler = new UptimeClientHandler(bootstrap, timer); public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( timeoutHandler, uptimeHandler); } }); bootstrap.setOption( "remoteAddress", new InetSocketAddress(host, port)); // Initiate the first connection attempt - the rest is handled by // UptimeClientHandler. bootstrap.connect(); } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length != 2) { System.err.println( "Usage: " + UptimeClient.class.getSimpleName() + " "); return; } // Parse options. String host = args[0]; int port = Integer.parseInt(args[1]); new UptimeClient(host, port).run(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/example/uptime/UptimeClientHandler.java000066400000000000000000000066601225554127700323100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.example.uptime; import java.net.ConnectException; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.timeout.ReadTimeoutException; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; /** * Keep reconnecting to the server while printing out the current uptime and * connection attempt status. */ public class UptimeClientHandler extends SimpleChannelUpstreamHandler { final ClientBootstrap bootstrap; private final Timer timer; private long startTime = -1; public UptimeClientHandler(ClientBootstrap bootstrap, Timer timer) { this.bootstrap = bootstrap; this.timer = timer; } InetSocketAddress getRemoteAddress() { return (InetSocketAddress) bootstrap.getOption("remoteAddress"); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) { println("Disconnected from: " + getRemoteAddress()); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) { println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + 's'); timer.newTimeout(new TimerTask() { public void run(Timeout timeout) throws Exception { println("Reconnecting to: " + getRemoteAddress()); bootstrap.connect(); } }, UptimeClient.RECONNECT_DELAY, TimeUnit.SECONDS); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { if (startTime < 0) { startTime = System.currentTimeMillis(); } println("Connected to: " + getRemoteAddress()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { Throwable cause = e.getCause(); if (cause instanceof ConnectException) { startTime = -1; println("Failed to connect: " + cause.getMessage()); } if (cause instanceof ReadTimeoutException) { // The connection was OK but there was no traffic for last period. println("Disconnecting due to no inbound traffic"); } else { cause.printStackTrace(); } ctx.getChannel().close(); } void println(String msg) { if (startTime < 0) { System.err.format("[SERVER IS DOWN] %s%n", msg); } else { System.err.format("[UPTIME: %5ds] %s%n", (System.currentTimeMillis() - startTime) / 1000, msg); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/000077500000000000000000000000001225554127700242145ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/000077500000000000000000000000001225554127700252715ustar00rootroot00000000000000PrematureChannelClosureException.java000066400000000000000000000023451225554127700345320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec; /** * Exception which should get thrown if a Channel got closed before it is expected */ public class PrematureChannelClosureException extends Exception { /** * */ private static final long serialVersionUID = 233460005724966593L; public PrematureChannelClosureException() { } public PrematureChannelClosureException(String msg) { super(msg); } public PrematureChannelClosureException(String msg, Throwable t) { super(msg, t); } public PrematureChannelClosureException(Throwable t) { super(t); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/base64/000077500000000000000000000000001225554127700263555ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/base64/Base64.java000066400000000000000000000340361225554127700302520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Robert Harder and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.handler.codec.base64; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.HeapChannelBufferFactory; /** * Utility class for {@link ChannelBuffer} that encodes and decodes to and from * Base64 notation. *

* The encoding and decoding algorithm in this class has been derived from * Robert Harder's Public Domain * Base64 Encoder/Decoder. * * @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.base64.Base64Dialect */ public final class Base64 { /** Maximum line length (76) of Base64 output. */ private static final int MAX_LINE_LENGTH = 76; /** The equals sign (=) as a byte. */ private static final byte EQUALS_SIGN = (byte) '='; /** The new line character (\n) as a byte. */ private static final byte NEW_LINE = (byte) '\n'; private static final byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding private static final byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding private static byte[] alphabet(Base64Dialect dialect) { if (dialect == null) { throw new NullPointerException("dialect"); } return dialect.alphabet; } private static byte[] decodabet(Base64Dialect dialect) { if (dialect == null) { throw new NullPointerException("dialect"); } return dialect.decodabet; } private static boolean breakLines(Base64Dialect dialect) { if (dialect == null) { throw new NullPointerException("dialect"); } return dialect.breakLinesByDefault; } public static ChannelBuffer encode(ChannelBuffer src) { return encode(src, Base64Dialect.STANDARD); } public static ChannelBuffer encode(ChannelBuffer src, Base64Dialect dialect) { return encode(src, breakLines(dialect), dialect); } public static ChannelBuffer encode( ChannelBuffer src, ChannelBufferFactory bufferFactory) { return encode(src, Base64Dialect.STANDARD, bufferFactory); } public static ChannelBuffer encode( ChannelBuffer src, Base64Dialect dialect, ChannelBufferFactory bufferFactory) { return encode(src, breakLines(dialect), dialect, bufferFactory); } public static ChannelBuffer encode(ChannelBuffer src, boolean breakLines) { return encode(src, breakLines, Base64Dialect.STANDARD); } public static ChannelBuffer encode( ChannelBuffer src, boolean breakLines, Base64Dialect dialect) { return encode(src, breakLines, dialect, HeapChannelBufferFactory.getInstance()); } public static ChannelBuffer encode( ChannelBuffer src, boolean breakLines, ChannelBufferFactory bufferFactory) { return encode(src, breakLines, Base64Dialect.STANDARD, bufferFactory); } public static ChannelBuffer encode( ChannelBuffer src, boolean breakLines, Base64Dialect dialect, ChannelBufferFactory bufferFactory) { if (src == null) { throw new NullPointerException("src"); } ChannelBuffer dest = encode( src, src.readerIndex(), src.readableBytes(), breakLines, dialect, bufferFactory); src.readerIndex(src.writerIndex()); return dest; } public static ChannelBuffer encode(ChannelBuffer src, int off, int len) { return encode(src, off, len, Base64Dialect.STANDARD); } public static ChannelBuffer encode(ChannelBuffer src, int off, int len, Base64Dialect dialect) { return encode(src, off, len, breakLines(dialect), dialect); } public static ChannelBuffer encode(ChannelBuffer src, int off, int len, ChannelBufferFactory bufferFactory) { return encode(src, off, len, Base64Dialect.STANDARD, bufferFactory); } public static ChannelBuffer encode( ChannelBuffer src, int off, int len, Base64Dialect dialect, ChannelBufferFactory bufferFactory) { return encode(src, off, len, breakLines(dialect), dialect, bufferFactory); } public static ChannelBuffer encode( ChannelBuffer src, int off, int len, boolean breakLines) { return encode(src, off, len, breakLines, Base64Dialect.STANDARD); } public static ChannelBuffer encode( ChannelBuffer src, int off, int len, boolean breakLines, Base64Dialect dialect) { return encode(src, off, len, breakLines, dialect, HeapChannelBufferFactory.getInstance()); } public static ChannelBuffer encode( ChannelBuffer src, int off, int len, boolean breakLines, ChannelBufferFactory bufferFactory) { return encode(src, off, len, breakLines, Base64Dialect.STANDARD, bufferFactory); } public static ChannelBuffer encode( ChannelBuffer src, int off, int len, boolean breakLines, Base64Dialect dialect, ChannelBufferFactory bufferFactory) { if (src == null) { throw new NullPointerException("src"); } if (dialect == null) { throw new NullPointerException("dialect"); } if (bufferFactory == null) { throw new NullPointerException("bufferFactory"); } int len43 = len * 4 / 3; ChannelBuffer dest = bufferFactory.getBuffer( src.order(), len43 + (len % 3 > 0? 4 : 0) + // Account for padding (breakLines? len43 / MAX_LINE_LENGTH : 0)); // New lines int d = 0; int e = 0; int len2 = len - 2; int lineLength = 0; for (; d < len2; d += 3, e += 4) { encode3to4(src, d + off, 3, dest, e, dialect); lineLength += 4; if (breakLines && lineLength == MAX_LINE_LENGTH) { dest.setByte(e + 4, NEW_LINE); e ++; lineLength = 0; } // end if: end of line } // end for: each piece of array if (d < len) { encode3to4(src, d + off, len - d, dest, e, dialect); e += 4; } // end if: some padding needed return dest.slice(0, e); } private static void encode3to4( ChannelBuffer src, int srcOffset, int numSigBytes, ChannelBuffer dest, int destOffset, Base64Dialect dialect) { byte[] ALPHABET = alphabet(dialect); // 1 2 3 // 01234567890123456789012345678901 Bit position // --------000000001111111122222222 Array position from threeBytes // --------| || || || | Six bit groups to index ALPHABET // >>18 >>12 >> 6 >> 0 Right shift necessary // 0x3f 0x3f 0x3f Additional AND // Create buffer with zero-padding if there are only one or two // significant bytes passed in the array. // We have to shift left 24 in order to flush out the 1's that appear // when Java treats a value as negative that is cast from a byte to an int. int inBuff = (numSigBytes > 0? src.getByte(srcOffset) << 24 >>> 8 : 0) | (numSigBytes > 1? src.getByte(srcOffset + 1) << 24 >>> 16 : 0) | (numSigBytes > 2? src.getByte(srcOffset + 2) << 24 >>> 24 : 0); switch (numSigBytes) { case 3: dest.setByte(destOffset , ALPHABET[inBuff >>> 18 ]); dest.setByte(destOffset + 1, ALPHABET[inBuff >>> 12 & 0x3f]); dest.setByte(destOffset + 2, ALPHABET[inBuff >>> 6 & 0x3f]); dest.setByte(destOffset + 3, ALPHABET[inBuff & 0x3f]); break; case 2: dest.setByte(destOffset , ALPHABET[inBuff >>> 18 ]); dest.setByte(destOffset + 1, ALPHABET[inBuff >>> 12 & 0x3f]); dest.setByte(destOffset + 2, ALPHABET[inBuff >>> 6 & 0x3f]); dest.setByte(destOffset + 3, EQUALS_SIGN); break; case 1: dest.setByte(destOffset , ALPHABET[inBuff >>> 18 ]); dest.setByte(destOffset + 1, ALPHABET[inBuff >>> 12 & 0x3f]); dest.setByte(destOffset + 2, EQUALS_SIGN); dest.setByte(destOffset + 3, EQUALS_SIGN); break; } } public static ChannelBuffer decode(ChannelBuffer src) { return decode(src, Base64Dialect.STANDARD); } public static ChannelBuffer decode(ChannelBuffer src, Base64Dialect dialect) { return decode(src, dialect, HeapChannelBufferFactory.getInstance()); } public static ChannelBuffer decode(ChannelBuffer src, ChannelBufferFactory bufferFactory) { return decode(src, Base64Dialect.STANDARD, bufferFactory); } public static ChannelBuffer decode(ChannelBuffer src, Base64Dialect dialect, ChannelBufferFactory bufferFactory) { if (src == null) { throw new NullPointerException("src"); } ChannelBuffer dest = decode(src, src.readerIndex(), src.readableBytes(), dialect, bufferFactory); src.readerIndex(src.writerIndex()); return dest; } public static ChannelBuffer decode( ChannelBuffer src, int off, int len) { return decode(src, off, len, Base64Dialect.STANDARD); } public static ChannelBuffer decode( ChannelBuffer src, int off, int len, Base64Dialect dialect) { return decode(src, off, len, dialect, HeapChannelBufferFactory.getInstance()); } public static ChannelBuffer decode( ChannelBuffer src, int off, int len, ChannelBufferFactory bufferFactory) { return decode(src, off, len, Base64Dialect.STANDARD, bufferFactory); } public static ChannelBuffer decode( ChannelBuffer src, int off, int len, Base64Dialect dialect, ChannelBufferFactory bufferFactory) { if (src == null) { throw new NullPointerException("src"); } if (dialect == null) { throw new NullPointerException("dialect"); } if (bufferFactory == null) { throw new NullPointerException("bufferFactory"); } byte[] DECODABET = decodabet(dialect); int len34 = len * 3 / 4; ChannelBuffer dest = bufferFactory.getBuffer(src.order(), len34); // Upper limit on size of output int outBuffPosn = 0; byte[] b4 = new byte[4]; int b4Posn = 0; int i; byte sbiCrop; byte sbiDecode; for (i = off; i < off + len; i ++) { sbiCrop = (byte) (src.getByte(i) & 0x7f); // Only the low seven bits sbiDecode = DECODABET[sbiCrop]; if (sbiDecode >= WHITE_SPACE_ENC) { // White space, Equals sign or better if (sbiDecode >= EQUALS_SIGN_ENC) { // Equals sign or better? b4[b4Posn ++] = sbiCrop; if (b4Posn > 3) { // Quartet built? outBuffPosn += decode4to3( b4, 0, dest, outBuffPosn, dialect); b4Posn = 0; // If that was the equals sign, break out of 'for' loop if (sbiCrop == EQUALS_SIGN) { break; } } } } else { throw new IllegalArgumentException( "bad Base64 input character at " + i + ": " + src.getUnsignedByte(i) + " (decimal)"); } } return dest.slice(0, outBuffPosn); } private static int decode4to3( byte[] src, int srcOffset, ChannelBuffer dest, int destOffset, Base64Dialect dialect) { byte[] DECODABET = decodabet(dialect); if (src[srcOffset + 2] == EQUALS_SIGN) { // Example: Dk== int outBuff = (DECODABET[src[srcOffset ]] & 0xFF) << 18 | (DECODABET[src[srcOffset + 1]] & 0xFF) << 12; dest.setByte(destOffset, (byte) (outBuff >>> 16)); return 1; } else if (src[srcOffset + 3] == EQUALS_SIGN) { // Example: DkL= int outBuff = (DECODABET[src[srcOffset ]] & 0xFF) << 18 | (DECODABET[src[srcOffset + 1]] & 0xFF) << 12 | (DECODABET[src[srcOffset + 2]] & 0xFF) << 6; dest.setByte(destOffset , (byte) (outBuff >>> 16)); dest.setByte(destOffset + 1, (byte) (outBuff >>> 8)); return 2; } else { // Example: DkLE int outBuff; try { outBuff = (DECODABET[src[srcOffset ]] & 0xFF) << 18 | (DECODABET[src[srcOffset + 1]] & 0xFF) << 12 | (DECODABET[src[srcOffset + 2]] & 0xFF) << 6 | DECODABET[src[srcOffset + 3]] & 0xFF; } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException("not encoded in Base64"); } dest.setByte(destOffset , (byte) (outBuff >> 16)); dest.setByte(destOffset + 1, (byte) (outBuff >> 8)); dest.setByte(destOffset + 2, (byte) outBuff); return 3; } } private Base64() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/base64/Base64Decoder.java000066400000000000000000000055231225554127700315370ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.base64; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; import org.jboss.netty.util.CharsetUtil; /** * Decodes a Base64-encoded {@link ChannelBuffer} or US-ASCII {@link String} * into a {@link ChannelBuffer}. Please note that this decoder must be used * with a proper {@link FrameDecoder} such as {@link DelimiterBasedFrameDecoder} * if you are using a stream-based transport such as TCP/IP. A typical decoder * setup for TCP/IP would be: *

 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder", new {@link DelimiterBasedFrameDecoder}(80, {@link Delimiters#nulDelimiter()}));
 * pipeline.addLast("base64Decoder", new {@link Base64Decoder}());
 *
 * // Encoder
 * pipeline.addLast("base64Encoder", new {@link Base64Encoder}());
 * 
* @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.base64.Base64 */ @Sharable public class Base64Decoder extends OneToOneDecoder { private final Base64Dialect dialect; public Base64Decoder() { this(Base64Dialect.STANDARD); } public Base64Decoder(Base64Dialect dialect) { if (dialect == null) { throw new NullPointerException("dialect"); } this.dialect = dialect; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof String) { msg = ChannelBuffers.copiedBuffer((String) msg, CharsetUtil.US_ASCII); } else if (!(msg instanceof ChannelBuffer)) { return msg; } ChannelBuffer src = (ChannelBuffer) msg; return Base64.decode( src, src.readerIndex(), src.readableBytes(), dialect); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/base64/Base64Dialect.java000066400000000000000000000262541225554127700315430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Robert Harder and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.handler.codec.base64; /** * Enumeration of supported Base64 dialects. *

* The internal lookup tables in this class has been derived from * Robert Harder's Public Domain * Base64 Encoder/Decoder. */ public enum Base64Dialect { /** * Standard Base64 encoding as described in the Section 3 of * RFC3548. */ STANDARD(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' }, new byte[] { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 -5, -5, // Whitespace: Tab and Linefeed -9, -9, // Decimal 11 - 12 -5, // Whitespace: Carriage Return -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 -9, -9, -9, -9, -9, // Decimal 27 - 31 -5, // Whitespace: Space -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 62, // Plus sign at decimal 43 -9, -9, -9, // Decimal 44 - 46 63, // Slash at decimal 47 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine -9, -9, -9, // Decimal 58 - 60 -1, // Equals sign at decimal 61 -9, -9, -9, // Decimal 62 - 64 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' -9, -9, -9, -9, // Decimal 123 - 126 /* -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ }, true), /** * Base64-like encoding that is URL-safe as described in the Section 4 of * RFC3548. It is * important to note that data encoded this way is not officially * valid Base64, or at the very least should not be called Base64 without * also specifying that is was encoded using the URL-safe dialect. */ URL_SAFE(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' }, new byte[] { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 -5, -5, // Whitespace: Tab and Linefeed -9, -9, // Decimal 11 - 12 -5, // Whitespace: Carriage Return -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 -9, -9, -9, -9, -9, // Decimal 27 - 31 -5, // Whitespace: Space -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 -9, // Plus sign at decimal 43 -9, // Decimal 44 62, // Minus sign at decimal 45 -9, // Decimal 46 -9, // Slash at decimal 47 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine -9, -9, -9, // Decimal 58 - 60 -1, // Equals sign at decimal 61 -9, -9, -9, // Decimal 62 - 64 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' -9, -9, -9, -9, // Decimal 91 - 94 63, // Underscore at decimal 95 -9, // Decimal 96 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' -9, -9, -9, -9, // Decimal 123 - 126 /*-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ }, false), /** * Special "ordered" dialect of Base64 described in * RFC1940. */ ORDERED(new byte[] { (byte) '-', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z' }, new byte[] { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 -5, -5, // Whitespace: Tab and Linefeed -9, -9, // Decimal 11 - 12 -5, // Whitespace: Carriage Return -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 -9, -9, -9, -9, -9, // Decimal 27 - 31 -5, // Whitespace: Space -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 -9, // Plus sign at decimal 43 -9, // Decimal 44 0, // Minus sign at decimal 45 -9, // Decimal 46 -9, // Slash at decimal 47 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine -9, -9, -9, // Decimal 58 - 60 -1, // Equals sign at decimal 61 -9, -9, -9, // Decimal 62 - 64 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M' 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z' -9, -9, -9, -9, // Decimal 91 - 94 37, // Underscore at decimal 95 -9, // Decimal 96 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm' 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z' -9, -9, -9, -9, // Decimal 123 - 126 /* -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ }, true); final byte[] alphabet; final byte[] decodabet; final boolean breakLinesByDefault; Base64Dialect(byte[] alphabet, byte[] decodabet, boolean breakLinesByDefault) { this.alphabet = alphabet; this.decodabet = decodabet; this.breakLinesByDefault = breakLinesByDefault; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/base64/Base64Encoder.java000066400000000000000000000050651225554127700315520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.base64; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * Encodes a {@link ChannelBuffer} into a Base64-encoded {@link ChannelBuffer}. * A typical setup for TCP/IP would be: *

 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder", new {@link DelimiterBasedFrameDecoder}(80, {@link Delimiters#nulDelimiter()}));
 * pipeline.addLast("base64Decoder", new {@link Base64Decoder}());
 *
 * // Encoder
 * pipeline.addLast("base64Encoder", new {@link Base64Encoder}());
 * 
* @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.base64.Base64 */ @Sharable public class Base64Encoder extends OneToOneEncoder { private final boolean breakLines; private final Base64Dialect dialect; public Base64Encoder() { this(true); } public Base64Encoder(boolean breakLines) { this(breakLines, Base64Dialect.STANDARD); } public Base64Encoder(boolean breakLines, Base64Dialect dialect) { if (dialect == null) { throw new NullPointerException("dialect"); } this.breakLines = breakLines; this.dialect = dialect; } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer)) { return msg; } ChannelBuffer src = (ChannelBuffer) msg; return Base64.encode( src, src.readerIndex(), src.readableBytes(), breakLines, dialect); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/base64/package-info.java000066400000000000000000000017531225554127700315520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder and decoder which transform a * Base64-encoded * {@link java.lang.String} or {@link org.jboss.netty.buffer.ChannelBuffer} * into a decoded {@link org.jboss.netty.buffer.ChannelBuffer} and vice versa. * * @apiviz.exclude OneToOne(Encoder|Decoder)$ */ package org.jboss.netty.handler.codec.base64; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/000077500000000000000000000000001225554127700276325ustar00rootroot00000000000000CompressionException.java000066400000000000000000000026421225554127700346020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.compression; import java.io.IOException; /** * An {@link IOException} that is raised when compression or decompression * failed. */ public class CompressionException extends RuntimeException { private static final long serialVersionUID = 5603413481274811897L; /** * Creates a new instance. */ public CompressionException() { } /** * Creates a new instance. */ public CompressionException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public CompressionException(String message) { super(message); } /** * Creates a new instance. */ public CompressionException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/JdkZlibEncoder.java000066400000000000000000000235721225554127700333370ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.compression; import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.CRC32; import java.util.zip.Deflater; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.handler.codec.oneone.OneToOneStrictEncoder; /** * Compresses a {@link ChannelBuffer} using the deflate algorithm. * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.compression.ZlibWrapper */ public class JdkZlibEncoder extends OneToOneStrictEncoder implements LifeCycleAwareChannelHandler { private final byte[] out = new byte[8192]; private final Deflater deflater; private final AtomicBoolean finished = new AtomicBoolean(); private volatile ChannelHandlerContext ctx; /* * GZIP support */ private final boolean gzip; private final CRC32 crc = new CRC32(); private static final byte[] gzipHeader = {0x1f, (byte) 0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0}; private boolean writeHeader = true; /** * Creates a new zlib encoder with the default compression level ({@code 6}) * and the default wrapper ({@link ZlibWrapper#ZLIB}). * * @throws CompressionException if failed to initialize zlib */ public JdkZlibEncoder() { this(6); } /** * Creates a new zlib encoder with the specified {@code compressionLevel} * and the default wrapper ({@link ZlibWrapper#ZLIB}). * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * * @throws CompressionException if failed to initialize zlib */ public JdkZlibEncoder(int compressionLevel) { this(ZlibWrapper.ZLIB, compressionLevel); } /** * Creates a new zlib encoder with the default compression level ({@code 6}) * and the specified wrapper. * * @throws CompressionException if failed to initialize zlib */ public JdkZlibEncoder(ZlibWrapper wrapper) { this(wrapper, 6); } /** * Creates a new zlib encoder with the specified {@code compressionLevel} * and the specified wrapper. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * * @throws CompressionException if failed to initialize zlib */ public JdkZlibEncoder(ZlibWrapper wrapper, int compressionLevel) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } if (wrapper == null) { throw new NullPointerException("wrapper"); } if (wrapper == ZlibWrapper.ZLIB_OR_NONE) { throw new IllegalArgumentException( "wrapper '" + ZlibWrapper.ZLIB_OR_NONE + "' is not " + "allowed for compression."); } gzip = wrapper == ZlibWrapper.GZIP; deflater = new Deflater(compressionLevel, wrapper != ZlibWrapper.ZLIB); } /** * Creates a new zlib encoder with the default compression level ({@code 6}) * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. * * @param dictionary the preset dictionary * * @throws CompressionException if failed to initialize zlib */ public JdkZlibEncoder(byte[] dictionary) { this(6, dictionary); } /** * Creates a new zlib encoder with the specified {@code compressionLevel} * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * @param dictionary the preset dictionary * * @throws CompressionException if failed to initialize zlib */ public JdkZlibEncoder(int compressionLevel, byte[] dictionary) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } if (dictionary == null) { throw new NullPointerException("dictionary"); } gzip = false; deflater = new Deflater(compressionLevel); deflater.setDictionary(dictionary); } public ChannelFuture close() { ChannelHandlerContext ctx = this.ctx; if (ctx == null) { throw new IllegalStateException("not added to a pipeline"); } return finishEncode(ctx, null); } public boolean isClosed() { return finished.get(); } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer) || finished.get()) { return msg; } ChannelBuffer uncompressed = (ChannelBuffer) msg; byte[] in = new byte[uncompressed.readableBytes()]; uncompressed.readBytes(in); int sizeEstimate = (int) Math.ceil(in.length * 1.001) + 12; ChannelBuffer compressed = ChannelBuffers.dynamicBuffer(sizeEstimate, channel.getConfig().getBufferFactory()); synchronized (deflater) { if (gzip) { crc.update(in); if (writeHeader) { compressed.writeBytes(gzipHeader); writeHeader = false; } } deflater.setInput(in); while (!deflater.needsInput()) { int numBytes = deflater.deflate(out, 0, out.length, Deflater.SYNC_FLUSH); compressed.writeBytes(out, 0, numBytes); } } return compressed; } @Override public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (evt instanceof ChannelStateEvent) { ChannelStateEvent e = (ChannelStateEvent) evt; switch (e.getState()) { case OPEN: case CONNECTED: case BOUND: if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) { finishEncode(ctx, evt); return; } } } super.handleDownstream(ctx, evt); } private ChannelFuture finishEncode(final ChannelHandlerContext ctx, final ChannelEvent evt) { ChannelFuture future = Channels.succeededFuture(ctx.getChannel()); if (!finished.compareAndSet(false, true)) { if (evt != null) { ctx.sendDownstream(evt); } return future; } ChannelBuffer footer = ChannelBuffers.dynamicBuffer(ctx.getChannel().getConfig().getBufferFactory()); synchronized (deflater) { deflater.finish(); while (!deflater.finished()) { int numBytes = deflater.deflate(out, 0, out.length); footer.writeBytes(out, 0, numBytes); } if (gzip) { int crcValue = (int) crc.getValue(); int uncBytes = deflater.getTotalIn(); footer.writeByte(crcValue); footer.writeByte(crcValue >>> 8); footer.writeByte(crcValue >>> 16); footer.writeByte(crcValue >>> 24); footer.writeByte(uncBytes); footer.writeByte(uncBytes >>> 8); footer.writeByte(uncBytes >>> 16); footer.writeByte(uncBytes >>> 24); } deflater.end(); } if (footer.readable()) { future = Channels.future(ctx.getChannel()); Channels.write(ctx, future, footer); } if (evt != null) { future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { ctx.sendDownstream(evt); } }); } return future; } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // Unused } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // Unused } public void afterRemove(ChannelHandlerContext ctx) throws Exception { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/ZlibDecoder.java000066400000000000000000000141151225554127700326650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.compression; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; import org.jboss.netty.util.internal.jzlib.JZlib; import org.jboss.netty.util.internal.jzlib.ZStream; /** * Decompresses a {@link ChannelBuffer} using the deflate algorithm. * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.compression.ZlibWrapper */ public class ZlibDecoder extends OneToOneDecoder { private final ZStream z = new ZStream(); private byte[] dictionary; private volatile boolean finished; /** * Creates a new instance with the default wrapper ({@link ZlibWrapper#ZLIB}). * * @throws CompressionException if failed to initialize zlib */ public ZlibDecoder() { this(ZlibWrapper.ZLIB); } /** * Creates a new instance with the specified wrapper. * * @throws CompressionException if failed to initialize zlib */ public ZlibDecoder(ZlibWrapper wrapper) { if (wrapper == null) { throw new NullPointerException("wrapper"); } synchronized (z) { int resultCode = z.inflateInit(ZlibUtil.convertWrapperType(wrapper)); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); } } } /** * Creates a new instance with the specified preset dictionary. The wrapper * is always {@link ZlibWrapper#ZLIB} because it is the only format that * supports the preset dictionary. * * @throws CompressionException if failed to initialize zlib */ public ZlibDecoder(byte[] dictionary) { if (dictionary == null) { throw new NullPointerException("dictionary"); } this.dictionary = dictionary; synchronized (z) { int resultCode; resultCode = z.inflateInit(JZlib.W_ZLIB); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); } } } /** * Returns {@code true} if and only if the end of the compressed stream * has been reached. */ public boolean isClosed() { return finished; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer) || finished) { return msg; } synchronized (z) { try { // Configure input. ChannelBuffer compressed = (ChannelBuffer) msg; byte[] in = new byte[compressed.readableBytes()]; compressed.readBytes(in); z.next_in = in; z.next_in_index = 0; z.avail_in = in.length; // Configure output. byte[] out = new byte[in.length << 1]; ChannelBuffer decompressed = ChannelBuffers.dynamicBuffer( compressed.order(), out.length, ctx.getChannel().getConfig().getBufferFactory()); z.next_out = out; z.next_out_index = 0; z.avail_out = out.length; loop: for (;;) { // Decompress 'in' into 'out' int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH); if (z.next_out_index > 0) { decompressed.writeBytes(out, 0, z.next_out_index); z.avail_out = out.length; } z.next_out_index = 0; switch (resultCode) { case JZlib.Z_NEED_DICT: if (dictionary == null) { ZlibUtil.fail(z, "decompression failure", resultCode); } else { resultCode = z.inflateSetDictionary(dictionary, dictionary.length); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "failed to set the dictionary", resultCode); } } break; case JZlib.Z_STREAM_END: finished = true; // Do not decode anymore. z.inflateEnd(); break loop; case JZlib.Z_OK: break; case JZlib.Z_BUF_ERROR: if (z.avail_in <= 0) { break loop; } break; default: ZlibUtil.fail(z, "decompression failure", resultCode); } } if (decompressed.writerIndex() != 0) { // readerIndex is always 0 return decompressed; } else { return null; } } finally { // Deference the external references explicitly to tell the VM that // the allocated byte arrays are temporary so that the call stack // can be utilized. // I'm not sure if the modern VMs do this optimization though. z.next_in = null; z.next_out = null; } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/ZlibEncoder.java000066400000000000000000000376201225554127700327050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.compression; import java.util.concurrent.atomic.AtomicBoolean; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.handler.codec.oneone.OneToOneStrictEncoder; import org.jboss.netty.util.internal.jzlib.JZlib; import org.jboss.netty.util.internal.jzlib.ZStream; /** * Compresses a {@link ChannelBuffer} using the deflate algorithm. * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.compression.ZlibWrapper */ public class ZlibEncoder extends OneToOneStrictEncoder implements LifeCycleAwareChannelHandler { private static final byte[] EMPTY_ARRAY = new byte[0]; private final ZStream z = new ZStream(); private final AtomicBoolean finished = new AtomicBoolean(); private volatile ChannelHandlerContext ctx; /** * Creates a new zlib encoder with the default compression level ({@code 6}), * default window bits ({@code 15}), default memory level ({@code 8}), * and the default wrapper ({@link ZlibWrapper#ZLIB}). * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder() { this(6); } /** * Creates a new zlib encoder with the specified {@code compressionLevel}, * default window bits ({@code 15}), default memory level ({@code 8}), * and the default wrapper ({@link ZlibWrapper#ZLIB}). * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(int compressionLevel) { this(ZlibWrapper.ZLIB, compressionLevel); } /** * Creates a new zlib encoder with the default compression level ({@code 6}), * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified wrapper. * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(ZlibWrapper wrapper) { this(wrapper, 6); } /** * Creates a new zlib encoder with the specified {@code compressionLevel}, * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified wrapper. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(ZlibWrapper wrapper, int compressionLevel) { this(wrapper, compressionLevel, 15, 8); } /** * Creates a new zlib encoder with the specified {@code compressionLevel}, * the specified {@code windowBits}, the specified {@code memLevel}, and * the specified wrapper. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * @param windowBits * The base two logarithm of the size of the history buffer. The * value should be in the range {@code 9} to {@code 15} inclusive. * Larger values result in better compression at the expense of * memory usage. The default value is {@code 15}. * @param memLevel * How much memory should be allocated for the internal compression * state. {@code 1} uses minimum memory and {@code 9} uses maximum * memory. Larger values result in better and faster compression * at the expense of memory usage. The default value is {@code 8} * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(ZlibWrapper wrapper, int compressionLevel, int windowBits, int memLevel) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } if (windowBits < 9 || windowBits > 15) { throw new IllegalArgumentException( "windowBits: " + windowBits + " (expected: 9-15)"); } if (memLevel < 1 || memLevel > 9) { throw new IllegalArgumentException( "memLevel: " + memLevel + " (expected: 1-9)"); } if (wrapper == null) { throw new NullPointerException("wrapper"); } if (wrapper == ZlibWrapper.ZLIB_OR_NONE) { throw new IllegalArgumentException( "wrapper '" + ZlibWrapper.ZLIB_OR_NONE + "' is not " + "allowed for compression."); } synchronized (z) { int resultCode = z.deflateInit(compressionLevel, windowBits, memLevel, ZlibUtil.convertWrapperType(wrapper)); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); } } } /** * Creates a new zlib encoder with the default compression level ({@code 6}), * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. * * @param dictionary the preset dictionary * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(byte[] dictionary) { this(6, dictionary); } /** * Creates a new zlib encoder with the specified {@code compressionLevel}, * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * @param dictionary the preset dictionary * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(int compressionLevel, byte[] dictionary) { this(compressionLevel, 15, 8, dictionary); } /** * Creates a new zlib encoder with the specified {@code compressionLevel}, * the specified {@code windowBits}, the specified {@code memLevel}, * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * @param windowBits * The base two logarithm of the size of the history buffer. The * value should be in the range {@code 9} to {@code 15} inclusive. * Larger values result in better compression at the expense of * memory usage. The default value is {@code 15}. * @param memLevel * How much memory should be allocated for the internal compression * state. {@code 1} uses minimum memory and {@code 9} uses maximum * memory. Larger values result in better and faster compression * at the expense of memory usage. The default value is {@code 8} * @param dictionary the preset dictionary * * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(int compressionLevel, int windowBits, int memLevel, byte[] dictionary) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } if (windowBits < 9 || windowBits > 15) { throw new IllegalArgumentException( "windowBits: " + windowBits + " (expected: 9-15)"); } if (memLevel < 1 || memLevel > 9) { throw new IllegalArgumentException( "memLevel: " + memLevel + " (expected: 1-9)"); } if (dictionary == null) { throw new NullPointerException("dictionary"); } synchronized (z) { int resultCode; resultCode = z.deflateInit(compressionLevel, windowBits, memLevel, JZlib.W_ZLIB); // Default: ZLIB format if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); } else { resultCode = z.deflateSetDictionary(dictionary, dictionary.length); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "failed to set the dictionary", resultCode); } } } } public ChannelFuture close() { ChannelHandlerContext ctx = this.ctx; if (ctx == null) { throw new IllegalStateException("not added to a pipeline"); } return finishEncode(ctx, null); } public boolean isClosed() { return finished.get(); } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer) || finished.get()) { return msg; } ChannelBuffer result; synchronized (z) { try { // Configure input. ChannelBuffer uncompressed = (ChannelBuffer) msg; byte[] in = new byte[uncompressed.readableBytes()]; uncompressed.readBytes(in); z.next_in = in; z.next_in_index = 0; z.avail_in = in.length; // Configure output. byte[] out = new byte[(int) Math.ceil(in.length * 1.001) + 12]; z.next_out = out; z.next_out_index = 0; z.avail_out = out.length; // Note that Z_PARTIAL_FLUSH has been deprecated. int resultCode = z.deflate(JZlib.Z_SYNC_FLUSH); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "compression failure", resultCode); } if (z.next_out_index != 0) { result = ctx.getChannel().getConfig().getBufferFactory().getBuffer( uncompressed.order(), out, 0, z.next_out_index); } else { result = ChannelBuffers.EMPTY_BUFFER; } } finally { // Deference the external references explicitly to tell the VM that // the allocated byte arrays are temporary so that the call stack // can be utilized. // I'm not sure if the modern VMs do this optimization though. z.next_in = null; z.next_out = null; } } return result; } @Override public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (evt instanceof ChannelStateEvent) { ChannelStateEvent e = (ChannelStateEvent) evt; switch (e.getState()) { case OPEN: case CONNECTED: case BOUND: if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) { finishEncode(ctx, evt); return; } } } super.handleDownstream(ctx, evt); } private ChannelFuture finishEncode(final ChannelHandlerContext ctx, final ChannelEvent evt) { if (!finished.compareAndSet(false, true)) { if (evt != null) { ctx.sendDownstream(evt); } return Channels.succeededFuture(ctx.getChannel()); } ChannelBuffer footer; ChannelFuture future; synchronized (z) { try { // Configure input. z.next_in = EMPTY_ARRAY; z.next_in_index = 0; z.avail_in = 0; // Configure output. byte[] out = new byte[32]; // room for ADLER32 + ZLIB / CRC32 + GZIP header z.next_out = out; z.next_out_index = 0; z.avail_out = out.length; // Write the ADLER32 checksum (stream footer). int resultCode = z.deflate(JZlib.Z_FINISH); if (resultCode != JZlib.Z_OK && resultCode != JZlib.Z_STREAM_END) { future = Channels.failedFuture( ctx.getChannel(), ZlibUtil.exception(z, "compression failure", resultCode)); footer = null; } else if (z.next_out_index != 0) { future = Channels.future(ctx.getChannel()); footer = ctx.getChannel().getConfig().getBufferFactory().getBuffer( out, 0, z.next_out_index); } else { // Note that we should never use a SucceededChannelFuture // here just in case any downstream handler or a sink wants // to notify a write error. future = Channels.future(ctx.getChannel()); footer = ChannelBuffers.EMPTY_BUFFER; } } finally { z.deflateEnd(); // Deference the external references explicitly to tell the VM that // the allocated byte arrays are temporary so that the call stack // can be utilized. // I'm not sure if the modern VMs do this optimization though. z.next_in = null; z.next_out = null; } } if (footer != null) { Channels.write(ctx, future, footer); } if (evt != null) { future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { ctx.sendDownstream(evt); } }); } return future; } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // Unused } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // Unused } public void afterRemove(ChannelHandlerContext ctx) throws Exception { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/ZlibUtil.java000066400000000000000000000035101225554127700322320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.compression; import org.jboss.netty.util.internal.jzlib.JZlib; import org.jboss.netty.util.internal.jzlib.ZStream; /** * Utility methods used by {@link ZlibEncoder} and {@link ZlibDecoder}. */ final class ZlibUtil { static void fail(ZStream z, String message, int resultCode) { throw exception(z, message, resultCode); } static CompressionException exception(ZStream z, String message, int resultCode) { return new CompressionException(message + " (" + resultCode + ')' + (z.msg != null? ": " + z.msg : "")); } static Enum convertWrapperType(ZlibWrapper wrapper) { Enum convertedWrapperType; switch (wrapper) { case NONE: convertedWrapperType = JZlib.W_NONE; break; case ZLIB: convertedWrapperType = JZlib.W_ZLIB; break; case GZIP: convertedWrapperType = JZlib.W_GZIP; break; case ZLIB_OR_NONE: convertedWrapperType = JZlib.W_ZLIB_OR_NONE; break; default: throw new Error(); } return convertedWrapperType; } private ZlibUtil() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/ZlibWrapper.java000066400000000000000000000025021225554127700327350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.compression; /** * The container file formats that wrap the stream compressed by the DEFLATE * algorithm. */ public enum ZlibWrapper { /** * The ZLIB wrapper as specified in RFC 1950. */ ZLIB, /** * The GZIP wrapper as specified in RFC 1952. */ GZIP, /** * Raw DEFLATE stream only (no header and no footer). */ NONE, /** * Try {@link #ZLIB} first and then {@link #NONE} if the first attempt fails. * Please note that you can specify this wrapper type only when decompressing. */ ZLIB_OR_NONE } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/compression/package-info.java000066400000000000000000000021651225554127700330250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder and decoder which compresses and decompresses {@link org.jboss.netty.buffer.ChannelBuffer}s * in a compression format such as zlib * and gzip. * * @apiviz.exclude \.codec\.(?!compression)[a-z0-9]+\. * @apiviz.exclude ^java\.lang\. * @apiviz.exclude \.channel\. * @apiviz.exclude Exception$ */ package org.jboss.netty.handler.codec.compression; // TODO Implement bzip2 and lzma handlers netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/000077500000000000000000000000001225554127700270405ustar00rootroot00000000000000AbstractCodecEmbedder.java000066400000000000000000000171001225554127700337540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineException; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.DefaultChannelPipeline; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import java.lang.reflect.Array; import java.util.ConcurrentModificationException; import java.util.LinkedList; import java.util.Queue; import static org.jboss.netty.channel.Channels.*; /** * A skeletal {@link CodecEmbedder} implementation. */ abstract class AbstractCodecEmbedder implements CodecEmbedder { private final Channel channel; private final ChannelPipeline pipeline; private final EmbeddedChannelSink sink = new EmbeddedChannelSink(); final Queue productQueue = new LinkedList(); /** * Creates a new embedder whose pipeline is composed of the specified * handlers. */ protected AbstractCodecEmbedder(ChannelHandler... handlers) { pipeline = new EmbeddedChannelPipeline(); configurePipeline(handlers); channel = new EmbeddedChannel(pipeline, sink); fireInitialEvents(); } /** * Creates a new embedder whose pipeline is composed of the specified * handlers. * * @param bufferFactory the {@link ChannelBufferFactory} to be used when * creating a new buffer. */ protected AbstractCodecEmbedder(ChannelBufferFactory bufferFactory, ChannelHandler... handlers) { this(handlers); getChannel().getConfig().setBufferFactory(bufferFactory); } private void fireInitialEvents() { // Fire the typical initial events. fireChannelOpen(channel); fireChannelBound(channel, channel.getLocalAddress()); fireChannelConnected(channel, channel.getRemoteAddress()); } private void configurePipeline(ChannelHandler... handlers) { if (handlers == null) { throw new NullPointerException("handlers"); } if (handlers.length == 0) { throw new IllegalArgumentException( "handlers should contain at least one " + ChannelHandler.class.getSimpleName() + '.'); } for (int i = 0; i < handlers.length; i ++) { ChannelHandler h = handlers[i]; if (h == null) { throw new NullPointerException("handlers[" + i + ']'); } pipeline.addLast(String.valueOf(i), handlers[i]); } pipeline.addLast("SINK", sink); } public boolean finish() { close(channel); fireChannelDisconnected(channel); fireChannelUnbound(channel); fireChannelClosed(channel); return !productQueue.isEmpty(); } /** * Returns the virtual {@link Channel} which will be used as a mock * during encoding and decoding. */ protected final Channel getChannel() { return channel; } /** * Returns {@code true} if and only if the produce queue is empty and * therefore {@link #poll()} will return {@code null}. */ protected final boolean isEmpty() { return productQueue.isEmpty(); } @SuppressWarnings("unchecked") public final E poll() { return (E) productQueue.poll(); } @SuppressWarnings("unchecked") public final E peek() { return (E) productQueue.peek(); } public final Object[] pollAll() { final int size = size(); Object[] a = new Object[size]; for (int i = 0; i < size; i ++) { E product = poll(); if (product == null) { throw new ConcurrentModificationException(); } a[i] = product; } return a; } @SuppressWarnings("unchecked") public final T[] pollAll(T[] a) { if (a == null) { throw new NullPointerException("a"); } final int size = size(); // Create a new array if the specified one is too small. if (a.length < size) { a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); } for (int i = 0;; i ++) { T product = (T) poll(); if (product == null) { break; } a[i] = product; } // Put the terminator if necessary. if (a.length > size) { a[size] = null; } return a; } public final int size() { return productQueue.size(); } public ChannelPipeline getPipeline() { return pipeline; } private final class EmbeddedChannelSink implements ChannelSink, ChannelUpstreamHandler { EmbeddedChannelSink() { } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) { handleEvent(e); } public void eventSunk(ChannelPipeline pipeline, ChannelEvent e) { handleEvent(e); } private void handleEvent(ChannelEvent e) { if (e instanceof MessageEvent) { boolean offered = productQueue.offer(((MessageEvent) e).getMessage()); assert offered; } else if (e instanceof ExceptionEvent) { throw new CodecEmbedderException(((ExceptionEvent) e).getCause()); } // Swallow otherwise. } public void exceptionCaught( ChannelPipeline pipeline, ChannelEvent e, ChannelPipelineException cause) throws Exception { Throwable actualCause = cause.getCause(); if (actualCause == null) { actualCause = cause; } throw new CodecEmbedderException(actualCause); } public ChannelFuture execute(ChannelPipeline pipeline, Runnable task) { try { task.run(); return succeededFuture(pipeline.getChannel()); } catch (Throwable t) { return failedFuture(pipeline.getChannel(), t); } } } private static final class EmbeddedChannelPipeline extends DefaultChannelPipeline { EmbeddedChannelPipeline() { } @Override protected void notifyHandlerException(ChannelEvent e, Throwable t) { while (t instanceof ChannelPipelineException && t.getCause() != null) { t = t.getCause(); } if (t instanceof CodecEmbedderException) { throw (CodecEmbedderException) t; } else { throw new CodecEmbedderException(t); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/CodecEmbedder.java000066400000000000000000000070201225554127700323470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import java.util.Collection; import org.jboss.netty.channel.ChannelPipeline; /** * A helper that wraps an encoder or a decoder (codec) so that they can be used * without doing actual I/O in unit tests or higher level codecs. Please refer * to {@link EncoderEmbedder} and {@link DecoderEmbedder} for more information. */ public interface CodecEmbedder { /** * Offers an input object to the pipeline of this embedder. * * @return {@code true} if and only if there is something to read in the * product queue (see {@link #poll()} and {@link #peek()}) */ boolean offer(Object input); /** * Signals the pipeline that the encoding or decoding has been finished and * no more data will be offered. * * @return {@code true} if and only if there is something to read in the * product queue (see {@link #poll()} and {@link #peek()}) */ boolean finish(); /** * Consumes an encoded or decoded output from the product queue. The output * object is generated by the offered input objects. * * @return an encoded or decoded object. * {@code null} if and only if there is no output object left in the * product queue. */ E poll(); /** * Reads an encoded or decoded output from the head of the product queue. * The difference from {@link #poll()} is that it does not remove the * retrieved object from the product queue. * * @return an encoded or decoded object. * {@code null} if and only if there is no output object left in the * product queue. */ E peek(); /** * Consumes all encoded or decoded output from the product queue. The * output object is generated by the offered input objects. The behavior * of this method is identical with {@link Collection#toArray()} except that * the product queue is cleared. * * @return an array of all encoded or decoded objects. * An empty array is returned if and only if there is no output * object left in the product queue. */ Object[] pollAll(); /** * Consumes all encoded or decoded output from the product queue. The * output object is generated by the offered input objects. The behavior * of this method is identical with {@link Collection#toArray(Object[])} * except that the product queue is cleared. * * @return an array of all encoded or decoded objects. * An empty array is returned if and only if there is no output * object left in the product queue. */ T[] pollAll(T[] a); /** * Returns the number of encoded or decoded output in the product queue. */ int size(); /** * Returns the {@link ChannelPipeline} that handles the input. */ ChannelPipeline getPipeline(); } CodecEmbedderException.java000066400000000000000000000027101225554127700341500ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; /** * A {@link RuntimeException} which is thrown when a {@link CodecEmbedder} * failed to encode or decode the specified input. * @apiviz.exclude */ public class CodecEmbedderException extends RuntimeException { private static final long serialVersionUID = -6283302594160331474L; /** * Creates a new instance. */ public CodecEmbedderException() { } /** * Creates a new instance. */ public CodecEmbedderException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public CodecEmbedderException(String message) { super(message); } /** * Creates a new instance. */ public CodecEmbedderException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/DecoderEmbedder.java000066400000000000000000000051711225554127700327040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.handler.codec.base64.Base64Decoder; import org.jboss.netty.handler.codec.string.StringDecoder; /** * A helper that wraps a decoder so that it can be used without doing actual * I/O in unit tests or higher level codecs. For example, you can decode a * Base64-encoded {@link ChannelBuffer} with {@link Base64Decoder} and * {@link StringDecoder} without setting up the {@link ChannelPipeline} and * other mock objects by yourself: *
 * {@link ChannelBuffer} base64Data = {@link ChannelBuffers}.copiedBuffer("Zm9vYmFy", CharsetUtil.US_ASCII);
 *
 * {@link DecoderEmbedder}<String> embedder = new {@link DecoderEmbedder}<String>(
 *         new {@link Base64Decoder}(), new {@link StringDecoder}());
 *
 * embedder.offer(base64Data);
 *
 * String decoded = embedder.poll();
 * assert decoded.equals("foobar");
 * 
* @apiviz.landmark * @see EncoderEmbedder */ public class DecoderEmbedder extends AbstractCodecEmbedder { /** * Creates a new embedder whose pipeline is composed of the specified * handlers. */ public DecoderEmbedder(ChannelUpstreamHandler... handlers) { super(handlers); } /** * Creates a new embedder whose pipeline is composed of the specified * handlers. * * @param bufferFactory the {@link ChannelBufferFactory} to be used when * creating a new buffer. */ public DecoderEmbedder(ChannelBufferFactory bufferFactory, ChannelUpstreamHandler... handlers) { super(bufferFactory, handlers); } public boolean offer(Object input) { fireMessageReceived(getChannel(), input); return !isEmpty(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/EmbeddedChannel.java000066400000000000000000000037541225554127700326760ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import java.net.SocketAddress; import org.jboss.netty.channel.AbstractChannel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.channel.DefaultChannelConfig; /** * TODO Make EmbeddedChannel implement ChannelConfig and ChannelSink to reduce overhead. * TODO Do not extend AbstractChannel to reduce overhead and remove the internal-use-only * constructor in AbstractChannel. */ class EmbeddedChannel extends AbstractChannel { private static final Integer DUMMY_ID = 0; private final ChannelConfig config; private final SocketAddress localAddress = new EmbeddedSocketAddress(); private final SocketAddress remoteAddress = new EmbeddedSocketAddress(); EmbeddedChannel(ChannelPipeline pipeline, ChannelSink sink) { super(DUMMY_ID, null, EmbeddedChannelFactory.INSTANCE, pipeline, sink); config = new DefaultChannelConfig(); } public ChannelConfig getConfig() { return config; } public SocketAddress getLocalAddress() { return localAddress; } public SocketAddress getRemoteAddress() { return remoteAddress; } public boolean isBound() { return true; } public boolean isConnected() { return true; } } EmbeddedChannelFactory.java000066400000000000000000000024011225554127700341330ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; /** */ final class EmbeddedChannelFactory implements ChannelFactory { static final ChannelFactory INSTANCE = new EmbeddedChannelFactory(); private EmbeddedChannelFactory() { } public Channel newChannel(ChannelPipeline pipeline) { throw new UnsupportedOperationException(); } public void releaseExternalResources() { // No external resources } public void shutdown() { // Nothing to shutdown } } EmbeddedSocketAddress.java000066400000000000000000000015121225554127700337730ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import java.net.SocketAddress; class EmbeddedSocketAddress extends SocketAddress { private static final long serialVersionUID = 1400788804624980619L; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/EncoderEmbedder.java000066400000000000000000000051711225554127700327160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.embedder; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.base64.Base64Encoder; import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.util.CharsetUtil; /** * A helper that wraps an encoder so that it can be used without doing actual * I/O in unit tests or higher level codecs. For example, you can encode a * {@link String} into a Base64-encoded {@link ChannelBuffer} with * {@link Base64Encoder} and {@link StringEncoder} without setting up the * {@link ChannelPipeline} and other mock objects by yourself: *
 * String data = "foobar";
 *
 * {@link EncoderEmbedder}<{@link ChannelBuffer}> embedder = new {@link EncoderEmbedder}<>(
 *         new {@link Base64Encoder}(), new {@link StringEncoder}());
 *
 * embedder.offer(data);
 *
 * {@link ChannelBuffer} encoded = embedder.poll();
 * assert encoded.toString({@link CharsetUtil}.US_ASCII).equals("Zm9vYmFy");
 * 
* @apiviz.landmark * @see DecoderEmbedder */ public class EncoderEmbedder extends AbstractCodecEmbedder { /** * Creates a new embedder whose pipeline is composed of the specified * handlers. */ public EncoderEmbedder(ChannelDownstreamHandler... handlers) { super(handlers); } /** * Creates a new embedder whose pipeline is composed of the specified * handlers. * * @param bufferFactory the {@link ChannelBufferFactory} to be used when * creating a new buffer. */ public EncoderEmbedder(ChannelBufferFactory bufferFactory, ChannelDownstreamHandler... handlers) { super(bufferFactory, handlers); } public boolean offer(Object input) { write(getChannel(), input).setSuccess(); return !isEmpty(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/embedder/package-info.java000066400000000000000000000015441225554127700322330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * A helper that wraps an encoder or a decoder so that they can be used without * doing actual I/O in unit tests or higher level codecs. * * @apiviz.exclude CodecEmbedder$ */ package org.jboss.netty.handler.codec.embedder; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/000077500000000000000000000000001225554127700263635ustar00rootroot00000000000000CorruptedFrameException.java000066400000000000000000000027141225554127700337540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; /** * An {@link Exception} which is thrown when the received frame data can not * be decoded by a {@link FrameDecoder} implementation. * * @apiviz.exclude */ public class CorruptedFrameException extends Exception { private static final long serialVersionUID = 3918052232492988408L; /** * Creates a new instance. */ public CorruptedFrameException() { } /** * Creates a new instance. */ public CorruptedFrameException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public CorruptedFrameException(String message) { super(message); } /** * Creates a new instance. */ public CorruptedFrameException(Throwable cause) { super(cause); } } DelimiterBasedFrameDecoder.java000066400000000000000000000332451225554127700342740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; /** * A decoder that splits the received {@link ChannelBuffer}s by one or more * delimiters. It is particularly useful for decoding the frames which ends * with a delimiter such as {@link Delimiters#nulDelimiter() NUL} or * {@linkplain Delimiters#lineDelimiter() newline characters}. * *

Predefined delimiters

*

* {@link Delimiters} defines frequently used delimiters for convenience' sake. * *

Specifying more than one delimiter

*

* {@link DelimiterBasedFrameDecoder} allows you to specify more than one * delimiter. If more than one delimiter is found in the buffer, it chooses * the delimiter which produces the shortest frame. For example, if you have * the following data in the buffer: *

 * +--------------+
 * | ABC\nDEF\r\n |
 * +--------------+
 * 
* a {@link DelimiterBasedFrameDecoder}{@code (}{@link Delimiters#lineDelimiter() Delimiters.lineDelimiter()}{@code )} * will choose {@code '\n'} as the first delimiter and produce two frames: *
 * +-----+-----+
 * | ABC | DEF |
 * +-----+-----+
 * 
* rather than incorrectly choosing {@code '\r\n'} as the first delimiter: *
 * +----------+
 * | ABC\nDEF |
 * +----------+
 * 
* * * @apiviz.uses org.jboss.netty.handler.codec.frame.Delimiters - - useful */ public class DelimiterBasedFrameDecoder extends FrameDecoder { private final ChannelBuffer[] delimiters; private final int maxFrameLength; private final boolean stripDelimiter; private final boolean failFast; private boolean discardingTooLongFrame; private int tooLongFrameLength; /** Set only when decoding with "\n" and "\r\n" as the delimiter. */ private final LineBasedFrameDecoder lineBasedDecoder; /** * Creates a new instance. * * @param maxFrameLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param delimiter the delimiter */ public DelimiterBasedFrameDecoder(int maxFrameLength, ChannelBuffer delimiter) { this(maxFrameLength, true, delimiter); } /** * Creates a new instance. * * @param maxFrameLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param stripDelimiter whether the decoded frame should strip out the * delimiter or not * @param delimiter the delimiter */ public DelimiterBasedFrameDecoder( int maxFrameLength, boolean stripDelimiter, ChannelBuffer delimiter) { this(maxFrameLength, stripDelimiter, false, delimiter); } /** * Creates a new instance. * * @param maxFrameLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param stripDelimiter whether the decoded frame should strip out the * delimiter or not * @param failFast If true, a {@link TooLongFrameException} is * thrown as soon as the decoder notices the length of the * frame will exceed maxFrameLength regardless of * whether the entire frame has been read. * If false, a {@link TooLongFrameException} is * thrown after the entire frame that exceeds * maxFrameLength has been read. * @param delimiter the delimiter */ public DelimiterBasedFrameDecoder( int maxFrameLength, boolean stripDelimiter, boolean failFast, ChannelBuffer delimiter) { this(maxFrameLength, stripDelimiter, failFast, new ChannelBuffer[] { delimiter.slice( delimiter.readerIndex(), delimiter.readableBytes()) }); } /** * Creates a new instance. * * @param maxFrameLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param delimiters the delimiters */ public DelimiterBasedFrameDecoder(int maxFrameLength, ChannelBuffer... delimiters) { this(maxFrameLength, true, delimiters); } /** * Creates a new instance. * * @param maxFrameLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param stripDelimiter whether the decoded frame should strip out the * delimiter or not * @param delimiters the delimiters */ public DelimiterBasedFrameDecoder( int maxFrameLength, boolean stripDelimiter, ChannelBuffer... delimiters) { this(maxFrameLength, stripDelimiter, false, delimiters); } /** * Creates a new instance. * * @param maxFrameLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param stripDelimiter whether the decoded frame should strip out the * delimiter or not * @param failFast If true, a {@link TooLongFrameException} is * thrown as soon as the decoder notices the length of the * frame will exceed maxFrameLength regardless of * whether the entire frame has been read. * If false, a {@link TooLongFrameException} is * thrown after the entire frame that exceeds * maxFrameLength has been read. * @param delimiters the delimiters */ public DelimiterBasedFrameDecoder( int maxFrameLength, boolean stripDelimiter, boolean failFast, ChannelBuffer... delimiters) { validateMaxFrameLength(maxFrameLength); if (delimiters == null) { throw new NullPointerException("delimiters"); } if (delimiters.length == 0) { throw new IllegalArgumentException("empty delimiters"); } if (isLineBased(delimiters) && !isSubclass()) { lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast); this.delimiters = null; } else { this.delimiters = new ChannelBuffer[delimiters.length]; for (int i = 0; i < delimiters.length; i ++) { ChannelBuffer d = delimiters[i]; validateDelimiter(d); this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes()); } lineBasedDecoder = null; } this.maxFrameLength = maxFrameLength; this.stripDelimiter = stripDelimiter; this.failFast = failFast; } /** Returns true if the delimiters are "\n" and "\r\n". */ private static boolean isLineBased(final ChannelBuffer[] delimiters) { if (delimiters.length != 2) { return false; } ChannelBuffer a = delimiters[0]; ChannelBuffer b = delimiters[1]; if (a.capacity() < b.capacity()) { a = delimiters[1]; b = delimiters[0]; } return a.capacity() == 2 && b.capacity() == 1 && a.getByte(0) == '\r' && a.getByte(1) == '\n' && b.getByte(0) == '\n'; } /** * Return {@code true} if the current instance is a subclass of DelimiterBasedFrameDecoder */ private boolean isSubclass() { return getClass() != DelimiterBasedFrameDecoder.class; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { if (lineBasedDecoder != null) { return lineBasedDecoder.decode(ctx, channel, buffer); } // Try all delimiters and choose the delimiter which yields the shortest frame. int minFrameLength = Integer.MAX_VALUE; ChannelBuffer minDelim = null; for (ChannelBuffer delim: delimiters) { int frameLength = indexOf(buffer, delim); if (frameLength >= 0 && frameLength < minFrameLength) { minFrameLength = frameLength; minDelim = delim; } } if (minDelim != null) { int minDelimLength = minDelim.capacity(); ChannelBuffer frame; if (discardingTooLongFrame) { // We've just finished discarding a very large frame. // Go back to the initial state. discardingTooLongFrame = false; buffer.skipBytes(minFrameLength + minDelimLength); int tooLongFrameLength = this.tooLongFrameLength; this.tooLongFrameLength = 0; if (!failFast) { fail(ctx, tooLongFrameLength); } return null; } if (minFrameLength > maxFrameLength) { // Discard read frame. buffer.skipBytes(minFrameLength + minDelimLength); fail(ctx, minFrameLength); return null; } if (stripDelimiter) { frame = extractFrame(buffer, buffer.readerIndex(), minFrameLength); } else { frame = extractFrame(buffer, buffer.readerIndex(), minFrameLength + minDelimLength); } buffer.skipBytes(minFrameLength + minDelimLength); return frame; } else { if (!discardingTooLongFrame) { if (buffer.readableBytes() > maxFrameLength) { // Discard the content of the buffer until a delimiter is found. tooLongFrameLength = buffer.readableBytes(); buffer.skipBytes(buffer.readableBytes()); discardingTooLongFrame = true; if (failFast) { fail(ctx, tooLongFrameLength); } } } else { // Still discarding the buffer since a delimiter is not found. tooLongFrameLength += buffer.readableBytes(); buffer.skipBytes(buffer.readableBytes()); } return null; } } private void fail(ChannelHandlerContext ctx, long frameLength) { if (frameLength > 0) { Channels.fireExceptionCaught( ctx.getChannel(), new TooLongFrameException( "frame length exceeds " + maxFrameLength + ": " + frameLength + " - discarded")); } else { Channels.fireExceptionCaught( ctx.getChannel(), new TooLongFrameException( "frame length exceeds " + maxFrameLength + " - discarding")); } } /** * Returns the number of bytes between the readerIndex of the haystack and * the first needle found in the haystack. -1 is returned if no needle is * found in the haystack. */ private static int indexOf(ChannelBuffer haystack, ChannelBuffer needle) { for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) { int haystackIndex = i; int needleIndex; for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) { if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) { break; } else { haystackIndex ++; if (haystackIndex == haystack.writerIndex() && needleIndex != needle.capacity() - 1) { return -1; } } } if (needleIndex == needle.capacity()) { // Found the needle from the haystack! return i - haystack.readerIndex(); } } return -1; } private static void validateDelimiter(ChannelBuffer delimiter) { if (delimiter == null) { throw new NullPointerException("delimiter"); } if (!delimiter.readable()) { throw new IllegalArgumentException("empty delimiter"); } } private static void validateMaxFrameLength(int maxFrameLength) { if (maxFrameLength <= 0) { throw new IllegalArgumentException( "maxFrameLength must be a positive integer: " + maxFrameLength); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/Delimiters.java000066400000000000000000000031361225554127700313320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * A set of commonly used delimiters for {@link DelimiterBasedFrameDecoder}. */ public final class Delimiters { /** * Returns a {@code NUL (0x00)} delimiter, which could be used for * Flash XML socket or any similar protocols. */ public static ChannelBuffer[] nulDelimiter() { return new ChannelBuffer[] { ChannelBuffers.wrappedBuffer(new byte[] { 0 }) }; } /** * Returns {@code CR ('\r')} and {@code LF ('\n')} delimiters, which could * be used for text-based line protocols. */ public static ChannelBuffer[] lineDelimiter() { return new ChannelBuffer[] { ChannelBuffers.wrappedBuffer(new byte[] { '\r', '\n' }), ChannelBuffers.wrappedBuffer(new byte[] { '\n' }), }; } private Delimiters() { // Unused } } FixedLengthFrameDecoder.java000066400000000000000000000060371225554127700336170ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; /** * A decoder that splits the received {@link ChannelBuffer}s by the fixed number * of bytes. For example, if you received the following four fragmented packets: *
 * +---+----+------+----+
 * | A | BC | DEFG | HI |
 * +---+----+------+----+
 * 
* A {@link FixedLengthFrameDecoder}{@code (3)} will decode them into the * following three packets with the fixed length: *
 * +-----+-----+-----+
 * | ABC | DEF | GHI |
 * +-----+-----+-----+
 * 
*/ public class FixedLengthFrameDecoder extends FrameDecoder { private final int frameLength; private final boolean allocateFullBuffer; /** * Calls {@link #FixedLengthFrameDecoder(int, boolean)} with {@code false} */ public FixedLengthFrameDecoder(int frameLength) { this(frameLength, false); } /** * Creates a new instance. * * @param frameLength * the length of the frame * @param allocateFullBuffer * {@code true} if the cumulative {@link ChannelBuffer} should use the * {@link #frameLength} as its initial size */ public FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer) { if (frameLength <= 0) { throw new IllegalArgumentException( "frameLength must be a positive integer: " + frameLength); } this.frameLength = frameLength; this.allocateFullBuffer = allocateFullBuffer; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { if (buffer.readableBytes() < frameLength) { return null; } else { ChannelBuffer frame = extractFrame(buffer, buffer.readerIndex(), frameLength); buffer.skipBytes(frameLength); return frame; } } @Override protected ChannelBuffer newCumulationBuffer(ChannelHandlerContext ctx, int minimumCapacity) { ChannelBufferFactory factory = ctx.getChannel().getConfig().getBufferFactory(); if (allocateFullBuffer) { return factory.getBuffer(frameLength); } return super.newCumulationBuffer(ctx, minimumCapacity); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/FrameDecoder.java000066400000000000000000000541341225554127700315550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.CompositeChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import java.net.SocketAddress; /** * Decodes the received {@link ChannelBuffer}s into a meaningful frame object. *

* In a stream-based transport such as TCP/IP, packets can be fragmented and * reassembled during transmission even in a LAN environment. For example, * let us assume you have received three packets: *

 * +-----+-----+-----+
 * | ABC | DEF | GHI |
 * +-----+-----+-----+
 * 
* because of the packet fragmentation, a server can receive them like the * following: *
 * +----+-------+---+---+
 * | AB | CDEFG | H | I |
 * +----+-------+---+---+
 * 
*

* {@link FrameDecoder} helps you defrag the received packets into one or more * meaningful frames that could be easily understood by the * application logic. In case of the example above, your {@link FrameDecoder} * implementation could defrag the received packets like the following: *

 * +-----+-----+-----+
 * | ABC | DEF | GHI |
 * +-----+-----+-----+
 * 
*

* The following code shows an example handler which decodes a frame whose * first 4 bytes header represents the length of the frame, excluding the * header. *

 * MESSAGE FORMAT
 * ==============
 *
 * Offset:  0        4                   (Length + 4)
 *          +--------+------------------------+
 * Fields:  | Length | Actual message content |
 *          +--------+------------------------+
 *
 * DECODER IMPLEMENTATION
 * ======================
 *
 * public class IntegerHeaderFrameDecoder extends {@link FrameDecoder} {
 *
 *   {@code @Override}
 *   protected Object decode({@link ChannelHandlerContext} ctx,
 *                           {@link Channel channel},
 *                           {@link ChannelBuffer} buf) throws Exception {
 *
 *     // Make sure if the length field was received.
 *     if (buf.readableBytes() < 4) {
 *        // The length field was not received yet - return null.
 *        // This method will be invoked again when more packets are
 *        // received and appended to the buffer.
 *        return null;
 *     }
 *
 *     // The length field is in the buffer.
 *
 *     // Mark the current buffer position before reading the length field
 *     // because the whole frame might not be in the buffer yet.
 *     // We will reset the buffer position to the marked position if
 *     // there's not enough bytes in the buffer.
 *     buf.markReaderIndex();
 *
 *     // Read the length field.
 *     int length = buf.readInt();
 *
 *     // Make sure if there's enough bytes in the buffer.
 *     if (buf.readableBytes() < length) {
 *        // The whole bytes were not received yet - return null.
 *        // This method will be invoked again when more packets are
 *        // received and appended to the buffer.
 *
 *        // Reset to the marked position to read the length field again
 *        // next time.
 *        buf.resetReaderIndex();
 *
 *        return null;
 *     }
 *
 *     // There's enough bytes in the buffer. Read it.
 *     {@link ChannelBuffer} frame = buf.readBytes(length);
 *
 *     // Successfully decoded a frame.  Return the decoded frame.
 *     return frame;
 *   }
 * }
 * 
* *

Returning a POJO rather than a {@link ChannelBuffer}

*

* Please note that you can return an object of a different type than * {@link ChannelBuffer} in your {@code decode()} and {@code decodeLast()} * implementation. For example, you could return a * POJO so that the next * {@link ChannelUpstreamHandler} receives a {@link MessageEvent} which * contains a POJO rather than a {@link ChannelBuffer}. * *

Replacing a decoder with another decoder in a pipeline

*

* If you are going to write a protocol multiplexer, you will probably want to * replace a {@link FrameDecoder} (protocol detector) with another * {@link FrameDecoder} or {@link ReplayingDecoder} (actual protocol decoder). * It is not possible to achieve this simply by calling * {@link ChannelPipeline#replace(ChannelHandler, String, ChannelHandler)}, but * some additional steps are required: *

 * public class FirstDecoder extends {@link FrameDecoder} {
 *
 *     public FirstDecoder() {
 *         super(true); // Enable unfold
 *     }
 *
 *     {@code @Override}
 *     protected Object decode({@link ChannelHandlerContext} ctx,
 *                             {@link Channel} channel,
 *                             {@link ChannelBuffer} buf) {
 *         ...
 *         // Decode the first message
 *         Object firstMessage = ...;
 *
 *         // Add the second decoder
 *         ctx.getPipeline().addLast("second", new SecondDecoder());
 *
 *         // Remove the first decoder (me)
 *         ctx.getPipeline().remove(this);
 *
 *         if (buf.readable()) {
 *             // Hand off the remaining data to the second decoder
 *             return new Object[] { firstMessage, buf.readBytes(buf.readableBytes()) };
 *         } else {
 *             // Nothing to hand off
 *             return firstMessage;
 *         }
 *     }
 * }
 * 
* * @apiviz.landmark */ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler { public static final int DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS = 1024; private boolean unfold; protected ChannelBuffer cumulation; private volatile ChannelHandlerContext ctx; private int copyThreshold; private int maxCumulationBufferComponents = DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS; protected FrameDecoder() { this(false); } protected FrameDecoder(boolean unfold) { this.unfold = unfold; } public final boolean isUnfold() { return unfold; } public final void setUnfold(boolean unfold) { if (ctx == null) { this.unfold = unfold; } else { throw new IllegalStateException( "decoder properties cannot be changed once the decoder is added to a pipeline."); } } /** * See {@link #setMaxCumulationBufferCapacity(int)} for explaintation of this setting * */ public final int getMaxCumulationBufferCapacity() { return copyThreshold; } /** * Set the maximal capacity of the internal cumulation ChannelBuffer to use * before the {@link FrameDecoder} tries to minimize the memory usage by * "byte copy". * * * What you use here really depends on your application and need. Using * {@link Integer#MAX_VALUE} will disable all byte copies but give you the * cost of a higher memory usage if big {@link ChannelBuffer}'s will be * received. * * By default a threshold of {@code 0} is used, which means it will * always copy to try to reduce memory usage * * * @param copyThreshold * the threshold (in bytes) or {@link Integer#MAX_VALUE} to * disable it. The value must be at least 0 * @throws IllegalStateException * get thrown if someone tries to change this setting after the * Decoder was added to the {@link ChannelPipeline} */ public final void setMaxCumulationBufferCapacity(int copyThreshold) { if (copyThreshold < 0) { throw new IllegalArgumentException("maxCumulationBufferCapacity must be >= 0"); } if (ctx == null) { this.copyThreshold = copyThreshold; } else { throw new IllegalStateException( "decoder properties cannot be changed once the decoder is added to a pipeline."); } } /** * Returns the maximum number of components in the cumulation buffer. If the number of * the components in the cumulation buffer exceeds this value, the components of the * cumulation buffer are consolidated into a single component, involving memory copies. * The default value of this property {@link #DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS}. */ public final int getMaxCumulationBufferComponents() { return maxCumulationBufferComponents; } /** * Sets the maximum number of components in the cumulation buffer. If the number of * the components in the cumulation buffer exceeds this value, the components of the * cumulation buffer are consolidated into a single component, involving memory copies. * The default value of this property is {@link #DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS} * and its minimum allowed value is {@code 2}. */ public final void setMaxCumulationBufferComponents(int maxCumulationBufferComponents) { if (maxCumulationBufferComponents < 2) { throw new IllegalArgumentException( "maxCumulationBufferComponents: " + maxCumulationBufferComponents + " (expected: >= 2)"); } if (ctx == null) { this.maxCumulationBufferComponents = maxCumulationBufferComponents; } else { throw new IllegalStateException( "decoder properties cannot be changed once the decoder is added to a pipeline."); } } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object m = e.getMessage(); if (!(m instanceof ChannelBuffer)) { ctx.sendUpstream(e); return; } ChannelBuffer input = (ChannelBuffer) m; if (!input.readable()) { return; } if (cumulation == null) { try { // the cumulation buffer is not created yet so just pass the input to callDecode(...) method callDecode(ctx, e.getChannel(), input, e.getRemoteAddress()); } finally { updateCumulation(ctx, input); } } else { input = appendToCumulation(input); try { callDecode(ctx, e.getChannel(), input, e.getRemoteAddress()); } finally { updateCumulation(ctx, input); } } } protected ChannelBuffer appendToCumulation(ChannelBuffer input) { ChannelBuffer cumulation = this.cumulation; assert cumulation.readable(); if (cumulation instanceof CompositeChannelBuffer) { // Make sure the resulting cumulation buffer has no more than the configured components. CompositeChannelBuffer composite = (CompositeChannelBuffer) cumulation; if (composite.numComponents() >= maxCumulationBufferComponents) { cumulation = composite.copy(); } } this.cumulation = input = ChannelBuffers.wrappedBuffer(cumulation, input); return input; } protected ChannelBuffer updateCumulation(ChannelHandlerContext ctx, ChannelBuffer input) { ChannelBuffer newCumulation; int readableBytes = input.readableBytes(); if (readableBytes > 0) { int inputCapacity = input.capacity(); // If input.readableBytes() == input.capacity() (i.e. input is full), // there's nothing to save from creating a new cumulation buffer // even if input.capacity() exceeds the threshold, because the new cumulation // buffer will have the same capacity and content with input. if (readableBytes < inputCapacity && inputCapacity > copyThreshold) { // At least one byte was consumed by callDecode() and input.capacity() // exceeded the threshold. cumulation = newCumulation = newCumulationBuffer(ctx, input.readableBytes()); cumulation.writeBytes(input); } else { // Nothing was consumed by callDecode() or input.capacity() did not // exceed the threshold. if (input.readerIndex() != 0) { cumulation = newCumulation = input.slice(); } else { cumulation = newCumulation = input; } } } else { cumulation = newCumulation = null; } return newCumulation; } @Override public void channelDisconnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { cleanup(ctx, e); } @Override public void channelClosed( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { cleanup(ctx, e); } @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { ctx.sendUpstream(e); } /** * Decodes the received packets so far into a frame. * * If an sub-class wants to extract a frame out of the buffer it should use * the {@link #extractFrame(ChannelBuffer, int, int)} method, * to make optimizations easier later. * * @param ctx the context of this handler * @param channel the current channel * @param buffer the cumulative buffer of received packets so far. * Note that the buffer might be empty, which means you * should not make an assumption that the buffer contains * at least one byte in your decoder implementation. * * @return the decoded frame if a full frame was received and decoded. * {@code null} if there's not enough data in the buffer to decode a frame. */ protected abstract Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception; /** * Decodes the received data so far into a frame when the channel is * disconnected. * * @param ctx the context of this handler * @param channel the current channel * @param buffer the cumulative buffer of received packets so far. * Note that the buffer might be empty, which means you * should not make an assumption that the buffer contains * at least one byte in your decoder implementation. * * @return the decoded frame if a full frame was received and decoded. * {@code null} if there's not enough data in the buffer to decode a frame. */ protected Object decodeLast( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { return decode(ctx, channel, buffer); } private void callDecode( ChannelHandlerContext context, Channel channel, ChannelBuffer cumulation, SocketAddress remoteAddress) throws Exception { while (cumulation.readable()) { int oldReaderIndex = cumulation.readerIndex(); Object frame = decode(context, channel, cumulation); if (frame == null) { if (oldReaderIndex == cumulation.readerIndex()) { // Seems like more data is required. // Let us wait for the next notification. break; } else { // Previous data has been discarded. // Probably it is reading on. continue; } } if (oldReaderIndex == cumulation.readerIndex()) { throw new IllegalStateException( "decode() method must read at least one byte " + "if it returned a frame (caused by: " + getClass() + ')'); } unfoldAndFireMessageReceived(context, remoteAddress, frame); } } protected final void unfoldAndFireMessageReceived( ChannelHandlerContext context, SocketAddress remoteAddress, Object result) { if (unfold) { if (result instanceof Object[]) { for (Object r: (Object[]) result) { Channels.fireMessageReceived(context, r, remoteAddress); } } else if (result instanceof Iterable) { for (Object r: (Iterable) result) { Channels.fireMessageReceived(context, r, remoteAddress); } } else { Channels.fireMessageReceived(context, result, remoteAddress); } } else { Channels.fireMessageReceived(context, result, remoteAddress); } } /** * Gets called on {@link #channelDisconnected(ChannelHandlerContext, ChannelStateEvent)} and * {@link #channelClosed(ChannelHandlerContext, ChannelStateEvent)} */ protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { try { ChannelBuffer cumulation = this.cumulation; if (cumulation == null) { return; } this.cumulation = null; if (cumulation.readable()) { // Make sure all frames are read before notifying a closed channel. callDecode(ctx, ctx.getChannel(), cumulation, null); } // Call decodeLast() finally. Please note that decodeLast() is // called even if there's nothing more to read from the buffer to // notify a user that the connection was closed explicitly. Object partialFrame = decodeLast(ctx, ctx.getChannel(), cumulation); if (partialFrame != null) { unfoldAndFireMessageReceived(ctx, null, partialFrame); } } finally { ctx.sendUpstream(e); } } /** * Create a new {@link ChannelBuffer} which is used for the cumulation. * Sub-classes may override this. * * @param ctx {@link ChannelHandlerContext} for this handler * @return buffer the {@link ChannelBuffer} which is used for cumulation */ protected ChannelBuffer newCumulationBuffer( ChannelHandlerContext ctx, int minimumCapacity) { ChannelBufferFactory factory = ctx.getChannel().getConfig().getBufferFactory(); return factory.getBuffer(Math.max(minimumCapacity, 256)); } /** * Replace this {@link FrameDecoder} in the {@link ChannelPipeline} with the given {@link ChannelHandler}. All * remaining bytes in the {@link ChannelBuffer} will get send to the new {@link ChannelHandler} that was used * as replacement * */ public void replace(String handlerName, ChannelHandler handler) { if (ctx == null) { throw new IllegalStateException( "Replace cann only be called once the FrameDecoder is added to the ChannelPipeline"); } ChannelPipeline pipeline = ctx.getPipeline(); pipeline.addAfter(ctx.getName(), handlerName, handler); try { if (cumulation != null) { Channels.fireMessageReceived(ctx, cumulation.readBytes(actualReadableBytes())); } } finally { pipeline.remove(this); } } /** * Returns the actual number of readable bytes in the internal cumulative * buffer of this decoder. You usually do not need to rely on this value * to write a decoder. Use it only when you muse use it at your own risk. * This method is a shortcut to {@link #internalBuffer() internalBuffer().readableBytes()}. */ protected int actualReadableBytes() { return internalBuffer().readableBytes(); } /** * Returns the internal cumulative buffer of this decoder. You usually * do not need to access the internal buffer directly to write a decoder. * Use it only when you must use it at your own risk. */ protected ChannelBuffer internalBuffer() { ChannelBuffer buf = cumulation; if (buf == null) { return ChannelBuffers.EMPTY_BUFFER; } return buf; } /** * Extract a Frame of the specified buffer. By default this implementation * will return a extract the sub-region of the buffer and create a new one. * If an sub-class want to extract a frame from the buffer it should use this method * by default. * * Be sure that this method MUST not modify the readerIndex of the given buffer * */ protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length) { ChannelBuffer frame = buffer.factory().getBuffer(length); frame.writeBytes(buffer, index, length); return frame; } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // Nothing to do.. } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // Nothing to do.. } public void afterRemove(ChannelHandlerContext ctx) throws Exception { // Nothing to do.. } } LengthFieldBasedFrameDecoder.java000066400000000000000000000443661225554127700345510ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; /** * A decoder that splits the received {@link ChannelBuffer}s dynamically by the * value of the length field in the message. It is particularly useful when you * decode a binary message which has an integer header field that represents the * length of the message body or the whole message. *

* {@link LengthFieldBasedFrameDecoder} has many configuration parameters so * that it can decode any message with a length field, which is often seen in * proprietary client-server protocols. Here are some example that will give * you the basic idea on which option does what. * *

2 bytes length field at offset 0, do not strip header

* * The value of the length field in this example is 12 (0x0C) which * represents the length of "HELLO, WORLD". By default, the decoder assumes * that the length field represents the number of the bytes that follows the * length field. Therefore, it can be decoded with the simplistic parameter * combination. *
 * lengthFieldOffset   = 0
 * lengthFieldLength   = 2
 * lengthAdjustment    = 0
 * initialBytesToStrip = 0 (= do not strip header)
 *
 * BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 * +--------+----------------+      +--------+----------------+
 * | Length | Actual Content |----->| Length | Actual Content |
 * | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
 * +--------+----------------+      +--------+----------------+
 * 
* *

2 bytes length field at offset 0, strip header

* * Because we can get the length of the content by calling * {@link ChannelBuffer#readableBytes()}, you might want to strip the length * field by specifying initialBytesToStrip. In this example, we * specified 2, that is same with the length of the length field, to * strip the first two bytes. *
 * lengthFieldOffset   = 0
 * lengthFieldLength   = 2
 * lengthAdjustment    = 0
 * initialBytesToStrip = 2 (= the length of the Length field)
 *
 * BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)
 * +--------+----------------+      +----------------+
 * | Length | Actual Content |----->| Actual Content |
 * | 0x000C | "HELLO, WORLD" |      | "HELLO, WORLD" |
 * +--------+----------------+      +----------------+
 * 
* *

2 bytes length field at offset 0, do not strip header, the length field * represents the length of the whole message

* * In most cases, the length field represents the length of the message body * only, as shown in the previous examples. However, in some protocols, the * length field represents the length of the whole message, including the * message header. In such a case, we specify a non-zero * lengthAdjustment. Because the length value in this example message * is always greater than the body length by 2, we specify -2 * as lengthAdjustment for compensation. *
 * lengthFieldOffset   =  0
 * lengthFieldLength   =  2
 * lengthAdjustment    = -2 (= the length of the Length field)
 * initialBytesToStrip =  0
 *
 * BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 * +--------+----------------+      +--------+----------------+
 * | Length | Actual Content |----->| Length | Actual Content |
 * | 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |
 * +--------+----------------+      +--------+----------------+
 * 
* *

3 bytes length field at the end of 5 bytes header, do not strip header

* * The following message is a simple variation of the first example. An extra * header value is prepended to the message. lengthAdjustment is zero * again because the decoder always takes the length of the prepended data into * account during frame length calculation. *
 * lengthFieldOffset   = 2 (= the length of Header 1)
 * lengthFieldLength   = 3
 * lengthAdjustment    = 0
 * initialBytesToStrip = 0
 *
 * BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
 * +----------+----------+----------------+      +----------+----------+----------------+
 * | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
 * |  0xCAFE  | 0x00000C | "HELLO, WORLD" |      |  0xCAFE  | 0x00000C | "HELLO, WORLD" |
 * +----------+----------+----------------+      +----------+----------+----------------+
 * 
* *

3 bytes length field at the beginning of 5 bytes header, do not strip header

* * This is an advanced example that shows the case where there is an extra * header between the length field and the message body. You have to specify a * positive lengthAdjustment so that the decoder counts the extra * header into the frame length calculation. *
 * lengthFieldOffset   = 0
 * lengthFieldLength   = 3
 * lengthAdjustment    = 2 (= the length of Header 1)
 * initialBytesToStrip = 0
 *
 * BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
 * +----------+----------+----------------+      +----------+----------+----------------+
 * |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
 * | 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |
 * +----------+----------+----------------+      +----------+----------+----------------+
 * 
* *

2 bytes length field at offset 1 in the middle of 4 bytes header, * strip the first header field and the length field

* * This is a combination of all the examples above. There are the prepended * header before the length field and the extra header after the length field. * The prepended header affects the lengthFieldOffset and the extra * header affects the lengthAdjustment. We also specified a non-zero * initialBytesToStrip to strip the length field and the prepended * header from the frame. If you don't want to strip the prepended header, you * could specify 0 for initialBytesToSkip. *
 * lengthFieldOffset   = 1 (= the length of HDR1)
 * lengthFieldLength   = 2
 * lengthAdjustment    = 1 (= the length of HDR2)
 * initialBytesToStrip = 3 (= the length of HDR1 + LEN)
 *
 * BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 * +------+--------+------+----------------+      +------+----------------+
 * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 * | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 * +------+--------+------+----------------+      +------+----------------+
 * 
* *

2 bytes length field at offset 1 in the middle of 4 bytes header, * strip the first header field and the length field, the length field * represents the length of the whole message

* * Let's give another twist to the previous example. The only difference from * the previous example is that the length field represents the length of the * whole message instead of the message body, just like the third example. * We have to count the length of HDR1 and Length into lengthAdjustment. * Please note that we don't need to take the length of HDR2 into account * because the length field already includes the whole header length. *
 * lengthFieldOffset   =  1
 * lengthFieldLength   =  2
 * lengthAdjustment    = -3 (= the length of HDR1 + LEN, negative)
 * initialBytesToStrip =  3
 *
 * BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 * +------+--------+------+----------------+      +------+----------------+
 * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 * | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 * +------+--------+------+----------------+      +------+----------------+
 * 
* * @see LengthFieldPrepender */ public class LengthFieldBasedFrameDecoder extends FrameDecoder { private final int maxFrameLength; private final int lengthFieldOffset; private final int lengthFieldLength; private final int lengthFieldEndOffset; private final int lengthAdjustment; private final int initialBytesToStrip; private final boolean failFast; private boolean discardingTooLongFrame; private long tooLongFrameLength; private long bytesToDiscard; /** * Creates a new instance. * * @param maxFrameLength * the maximum length of the frame. If the length of the frame is * greater than this value, {@link TooLongFrameException} will be * thrown. * @param lengthFieldOffset * the offset of the length field * @param lengthFieldLength * the length of the length field */ public LengthFieldBasedFrameDecoder( int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) { this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0); } /** * Creates a new instance. * * @param maxFrameLength * the maximum length of the frame. If the length of the frame is * greater than this value, {@link TooLongFrameException} will be * thrown. * @param lengthFieldOffset * the offset of the length field * @param lengthFieldLength * the length of the length field * @param lengthAdjustment * the compensation value to add to the value of the length field * @param initialBytesToStrip * the number of first bytes to strip out from the decoded frame */ public LengthFieldBasedFrameDecoder( int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) { this( maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, false); } /** * Creates a new instance. * * @param maxFrameLength * the maximum length of the frame. If the length of the frame is * greater than this value, {@link TooLongFrameException} will be * thrown. * @param lengthFieldOffset * the offset of the length field * @param lengthFieldLength * the length of the length field * @param lengthAdjustment * the compensation value to add to the value of the length field * @param initialBytesToStrip * the number of first bytes to strip out from the decoded frame * @param failFast * If true, a {@link TooLongFrameException} is thrown as * soon as the decoder notices the length of the frame will exceed * maxFrameLength regardless of whether the entire frame * has been read. If false, a {@link TooLongFrameException} * is thrown after the entire frame that exceeds maxFrameLength * has been read. */ public LengthFieldBasedFrameDecoder( int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) { if (maxFrameLength <= 0) { throw new IllegalArgumentException( "maxFrameLength must be a positive integer: " + maxFrameLength); } if (lengthFieldOffset < 0) { throw new IllegalArgumentException( "lengthFieldOffset must be a non-negative integer: " + lengthFieldOffset); } if (initialBytesToStrip < 0) { throw new IllegalArgumentException( "initialBytesToStrip must be a non-negative integer: " + initialBytesToStrip); } if (lengthFieldLength != 1 && lengthFieldLength != 2 && lengthFieldLength != 3 && lengthFieldLength != 4 && lengthFieldLength != 8) { throw new IllegalArgumentException( "lengthFieldLength must be either 1, 2, 3, 4, or 8: " + lengthFieldLength); } if (lengthFieldOffset > maxFrameLength - lengthFieldLength) { throw new IllegalArgumentException( "maxFrameLength (" + maxFrameLength + ") " + "must be equal to or greater than " + "lengthFieldOffset (" + lengthFieldOffset + ") + " + "lengthFieldLength (" + lengthFieldLength + ")."); } this.maxFrameLength = maxFrameLength; this.lengthFieldOffset = lengthFieldOffset; this.lengthFieldLength = lengthFieldLength; this.lengthAdjustment = lengthAdjustment; lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength; this.initialBytesToStrip = initialBytesToStrip; this.failFast = failFast; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { if (discardingTooLongFrame) { long bytesToDiscard = this.bytesToDiscard; int localBytesToDiscard = (int) Math.min(bytesToDiscard, buffer.readableBytes()); buffer.skipBytes(localBytesToDiscard); bytesToDiscard -= localBytesToDiscard; this.bytesToDiscard = bytesToDiscard; failIfNecessary(ctx, false); return null; } if (buffer.readableBytes() < lengthFieldEndOffset) { return null; } int actualLengthFieldOffset = buffer.readerIndex() + lengthFieldOffset; long frameLength; switch (lengthFieldLength) { case 1: frameLength = buffer.getUnsignedByte(actualLengthFieldOffset); break; case 2: frameLength = buffer.getUnsignedShort(actualLengthFieldOffset); break; case 3: frameLength = buffer.getUnsignedMedium(actualLengthFieldOffset); break; case 4: frameLength = buffer.getUnsignedInt(actualLengthFieldOffset); break; case 8: frameLength = buffer.getLong(actualLengthFieldOffset); break; default: throw new Error("should not reach here"); } if (frameLength < 0) { buffer.skipBytes(lengthFieldEndOffset); throw new CorruptedFrameException( "negative pre-adjustment length field: " + frameLength); } frameLength += lengthAdjustment + lengthFieldEndOffset; if (frameLength < lengthFieldEndOffset) { buffer.skipBytes(lengthFieldEndOffset); throw new CorruptedFrameException( "Adjusted frame length (" + frameLength + ") is less " + "than lengthFieldEndOffset: " + lengthFieldEndOffset); } if (frameLength > maxFrameLength) { // Enter the discard mode and discard everything received so far. discardingTooLongFrame = true; tooLongFrameLength = frameLength; bytesToDiscard = frameLength - buffer.readableBytes(); buffer.skipBytes(buffer.readableBytes()); failIfNecessary(ctx, true); return null; } // never overflows because it's less than maxFrameLength int frameLengthInt = (int) frameLength; if (buffer.readableBytes() < frameLengthInt) { return null; } if (initialBytesToStrip > frameLengthInt) { buffer.skipBytes(frameLengthInt); throw new CorruptedFrameException( "Adjusted frame length (" + frameLength + ") is less " + "than initialBytesToStrip: " + initialBytesToStrip); } buffer.skipBytes(initialBytesToStrip); // extract frame int readerIndex = buffer.readerIndex(); int actualFrameLength = frameLengthInt - initialBytesToStrip; ChannelBuffer frame = extractFrame(buffer, readerIndex, actualFrameLength); buffer.readerIndex(readerIndex + actualFrameLength); return frame; } private void failIfNecessary(ChannelHandlerContext ctx, boolean firstDetectionOfTooLongFrame) { if (bytesToDiscard == 0) { // Reset to the initial state and tell the handlers that // the frame was too large. long tooLongFrameLength = this.tooLongFrameLength; this.tooLongFrameLength = 0; discardingTooLongFrame = false; if (!failFast || failFast && firstDetectionOfTooLongFrame) { fail(ctx, tooLongFrameLength); } } else { // Keep discarding and notify handlers if necessary. if (failFast && firstDetectionOfTooLongFrame) { fail(ctx, tooLongFrameLength); } } } private void fail(ChannelHandlerContext ctx, long frameLength) { if (frameLength > 0) { Channels.fireExceptionCaught( ctx.getChannel(), new TooLongFrameException( "Adjusted frame length exceeds " + maxFrameLength + ": " + frameLength + " - discarded")); } else { Channels.fireExceptionCaught( ctx.getChannel(), new TooLongFrameException( "Adjusted frame length exceeds " + maxFrameLength + " - discarding")); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/LengthFieldPrepender.java000066400000000000000000000123041225554127700332600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import static org.jboss.netty.buffer.ChannelBuffers.*; import java.nio.ByteOrder; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * An encoder that prepends the length of the message. The length value is * prepended as a binary form. It is encoded in either big endian or little * endian depending on the default {@link ByteOrder} of the current * {@link ChannelBufferFactory}. *

* For example, {@link LengthFieldPrepender}(2) will encode the * following 12-bytes string: *

 * +----------------+
 * | "HELLO, WORLD" |
 * +----------------+
 * 
* into the following: *
 * +--------+----------------+
 * + 0x000C | "HELLO, WORLD" |
 * +--------+----------------+
 * 
* If you turned on the {@code lengthIncludesLengthFieldLength} flag in the * constructor, the encoded data would look like the following * (12 (original data) + 2 (prepended data) = 14 (0xE)): *
 * +--------+----------------+
 * + 0x000E | "HELLO, WORLD" |
 * +--------+----------------+
 * 
*/ @Sharable public class LengthFieldPrepender extends OneToOneEncoder { private final int lengthFieldLength; private final boolean lengthIncludesLengthFieldLength; /** * Creates a new instance. * * @param lengthFieldLength the length of the prepended length field. * Only 1, 2, 3, 4, and 8 are allowed. * * @throws IllegalArgumentException * if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8 */ public LengthFieldPrepender(int lengthFieldLength) { this(lengthFieldLength, false); } /** * Creates a new instance. * * @param lengthFieldLength the length of the prepended length field. * Only 1, 2, 3, 4, and 8 are allowed. * @param lengthIncludesLengthFieldLength * if {@code true}, the length of the prepended * length field is added to the value of the * prepended length field. * * @throws IllegalArgumentException * if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8 */ public LengthFieldPrepender( int lengthFieldLength, boolean lengthIncludesLengthFieldLength) { if (lengthFieldLength != 1 && lengthFieldLength != 2 && lengthFieldLength != 3 && lengthFieldLength != 4 && lengthFieldLength != 8) { throw new IllegalArgumentException( "lengthFieldLength must be either 1, 2, 3, 4, or 8: " + lengthFieldLength); } this.lengthFieldLength = lengthFieldLength; this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength; } @Override protected Object encode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer)) { return msg; } ChannelBuffer body = (ChannelBuffer) msg; ChannelBuffer header = channel.getConfig().getBufferFactory().getBuffer(body.order(), lengthFieldLength); int length = lengthIncludesLengthFieldLength? body.readableBytes() + lengthFieldLength : body.readableBytes(); switch (lengthFieldLength) { case 1: if (length >= 256) { throw new IllegalArgumentException( "length does not fit into a byte: " + length); } header.writeByte((byte) length); break; case 2: if (length >= 65536) { throw new IllegalArgumentException( "length does not fit into a short integer: " + length); } header.writeShort((short) length); break; case 3: if (length >= 16777216) { throw new IllegalArgumentException( "length does not fit into a medium integer: " + length); } header.writeMedium(length); break; case 4: header.writeInt(length); break; case 8: header.writeLong(length); break; default: throw new Error("should not reach here"); } return wrappedBuffer(header, body); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/LineBasedFrameDecoder.java000066400000000000000000000141001225554127700333110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; /** * A decoder that splits the received {@link ChannelBuffer}s on line endings. *

* Both {@code "\n"} and {@code "\r\n"} are handled. * For a more general delimiter-based decoder, see {@link DelimiterBasedFrameDecoder}. */ public class LineBasedFrameDecoder extends FrameDecoder { /** Maximum length of a frame we're willing to decode. */ private final int maxLength; /** Whether or not to throw an exception as soon as we exceed maxLength. */ private final boolean failFast; private final boolean stripDelimiter; /** True if we're discarding input because we're already over maxLength. */ private boolean discarding; private int discardedBytes; /** * Creates a new decoder. * @param maxLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. */ public LineBasedFrameDecoder(final int maxLength) { this(maxLength, true, false); } /** * Creates a new decoder. * @param maxLength the maximum length of the decoded frame. * A {@link TooLongFrameException} is thrown if * the length of the frame exceeds this value. * @param stripDelimiter whether the decoded frame should strip out the * delimiter or not * @param failFast If true, a {@link TooLongFrameException} is * thrown as soon as the decoder notices the length of the * frame will exceed maxFrameLength regardless of * whether the entire frame has been read. * If false, a {@link TooLongFrameException} is * thrown after the entire frame that exceeds * maxFrameLength has been read. */ public LineBasedFrameDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) { this.maxLength = maxLength; this.failFast = failFast; this.stripDelimiter = stripDelimiter; } @Override protected Object decode(final ChannelHandlerContext ctx, final Channel channel, final ChannelBuffer buffer) throws Exception { final int eol = findEndOfLine(buffer); if (!discarding) { if (eol >= 0) { final ChannelBuffer frame; final int length = eol - buffer.readerIndex(); final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1; if (length > maxLength) { buffer.readerIndex(eol + delimLength); fail(ctx, length); return null; } try { if (stripDelimiter) { frame = extractFrame(buffer, buffer.readerIndex(), length); } else { frame = extractFrame(buffer, buffer.readerIndex(), length + delimLength); } } finally { buffer.skipBytes(length + delimLength); } return frame; } else { final int length = buffer.readableBytes(); if (length > maxLength) { discardedBytes = length; buffer.readerIndex(buffer.writerIndex()); discarding = true; if (failFast) { fail(ctx, "over " + discardedBytes); } } return null; } } else { if (eol >= 0) { final int length = discardedBytes + eol - buffer.readerIndex(); final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1; buffer.readerIndex(eol + delimLength); discardedBytes = 0; discarding = false; if (!failFast) { fail(ctx, length); } } else { discardedBytes = buffer.readableBytes(); buffer.readerIndex(buffer.writerIndex()); } return null; } } private void fail(final ChannelHandlerContext ctx, int length) { fail(ctx, String.valueOf(length)); } private void fail(final ChannelHandlerContext ctx, String length) { Channels.fireExceptionCaught( ctx.getChannel(), new TooLongFrameException( "frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')')); } /** * Returns the index in the buffer of the end of line found. * Returns -1 if no end of line was found in the buffer. */ private static int findEndOfLine(final ChannelBuffer buffer) { final int n = buffer.writerIndex(); for (int i = buffer.readerIndex(); i < n; i ++) { final byte b = buffer.getByte(i); if (b == '\n') { return i; } else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') { return i; // \r\n } } return -1; // Not found. } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/TooLongFrameException.java000066400000000000000000000026531225554127700334470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; /** * An {@link Exception} which is thrown when the length of the frame * decoded is greater than the maximum. * * @apiviz.exclude */ public class TooLongFrameException extends Exception { private static final long serialVersionUID = -1995801950698951640L; /** * Creates a new instance. */ public TooLongFrameException() { } /** * Creates a new instance. */ public TooLongFrameException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public TooLongFrameException(String message) { super(message); } /** * Creates a new instance. */ public TooLongFrameException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/frame/package-info.java000066400000000000000000000020171225554127700315520ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Extensible decoder and its common implementations which deal with the * packet fragmentation and reassembly issue found in a stream-based transport * such as TCP/IP. * * @apiviz.exclude OneToOne(Encoder|Decoder)$ * @apiviz.exclude \.(Simple)?Channel[A-Za-z]*Handler$ * @apiviz.exclude \.codec\.[a-eg-z][a-z0-9]*\. * @apiviz.exclude \.ssl\. */ package org.jboss.netty.handler.codec.frame; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/000077500000000000000000000000001225554127700262505ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/Cookie.java000066400000000000000000000070161225554127700303300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Set; /** * An HTTP Cookie. */ public interface Cookie extends Comparable { /** * Returns the name of this cookie. */ String getName(); /** * Returns the value of this cookie. */ String getValue(); /** * Sets the value of this cookie. */ void setValue(String value); /** * Returns the domain of this cookie. */ String getDomain(); /** * Sets the domain of this cookie. */ void setDomain(String domain); /** * Returns the path of this cookie. */ String getPath(); /** * Sets the path of this cookie. */ void setPath(String path); /** * Returns the comment of this cookie. */ String getComment(); /** * Sets the comment of this cookie. */ void setComment(String comment); /** * Returns the max age of this cookie in seconds. */ int getMaxAge(); /** * Sets the max age of this cookie in seconds. If {@code 0} is specified, * this cookie will be removed by browser because it will be expired * immediately. If {@link Integer#MIN_VALUE} is specified, this cookie will be removed * when a user terminates browser. */ void setMaxAge(int maxAge); /** * Returns the version of this cookie. */ int getVersion(); /** * Sets the version of this cookie. */ void setVersion(int version); /** * Returns the secure flag of this cookie. */ boolean isSecure(); /** * Sets the secure flag of this cookie. */ void setSecure(boolean secure); /** * Returns if this cookie cannot be accessed through client side script. * This flag works only if the browser supports it. For more information, * see here. */ boolean isHttpOnly(); /** * Sets if this cookie cannot be accessed through client side script. * This flag works only if the browser supports it. For more information, * see here. */ void setHttpOnly(boolean httpOnly); /** * Returns the comment URL of this cookie. */ String getCommentUrl(); /** * Sets the comment URL of this cookie. */ void setCommentUrl(String commentUrl); /** * Returns the discard flag of this cookie. */ boolean isDiscard(); /** * Sets the discard flag of this cookie. */ void setDiscard(boolean discard); /** * Returns the ports of this cookie. */ Set getPorts(); /** * Sets the ports of this cookie. */ void setPorts(int... ports); /** * Sets the ports of this cookie. */ void setPorts(Iterable ports); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/CookieDateFormat.java000066400000000000000000000021201225554127700322660ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; /** * @deprecated use {@link HttpHeaderDateFormat} */ @Deprecated final class CookieDateFormat extends SimpleDateFormat { private static final long serialVersionUID = 1789486337887402640L; CookieDateFormat() { super("E, d-MMM-y HH:mm:ss z", Locale.ENGLISH); setTimeZone(TimeZone.getTimeZone("GMT")); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/CookieDecoder.java000066400000000000000000000254141225554127700316200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.util.internal.StringUtil; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * Decodes an HTTP header value into {@link Cookie}s. This decoder can decode * the HTTP cookie version 0, 1, and 2. * *

 * {@link HttpRequest} req = ...;
 * String value = req.getHeader("Cookie");
 * Set<{@link Cookie}> cookies = new {@link CookieDecoder}().decode(value);
 * 
* * @see CookieEncoder * * @apiviz.stereotype utility * @apiviz.has org.jboss.netty.handler.codec.http.Cookie oneway - - decodes */ public class CookieDecoder { private static final char COMMA = ','; /** * Creates a new decoder. */ public CookieDecoder() { } /** * @deprecated Use {@link #CookieDecoder()} instead. */ @Deprecated public CookieDecoder(@SuppressWarnings("unused") boolean lenient) { } /** * Decodes the specified HTTP header value into {@link Cookie}s. * * @return the decoded {@link Cookie}s */ public Set decode(String header) { List names = new ArrayList(8); List values = new ArrayList(8); extractKeyValuePairs(header, names, values); if (names.isEmpty()) { return Collections.emptySet(); } int i; int version = 0; // $Version is the only attribute that can appear before the actual // cookie name-value pair. if (names.get(0).equalsIgnoreCase(CookieHeaderNames.VERSION)) { try { version = Integer.parseInt(values.get(0)); } catch (NumberFormatException e) { // Ignore. } i = 1; } else { i = 0; } if (names.size() <= i) { // There's a version attribute, but nothing more. return Collections.emptySet(); } Set cookies = new TreeSet(); for (; i < names.size(); i ++) { String name = names.get(i); String value = values.get(i); if (value == null) { value = ""; } Cookie c = new DefaultCookie(name, value); boolean discard = false; boolean secure = false; boolean httpOnly = false; String comment = null; String commentURL = null; String domain = null; String path = null; int maxAge = Integer.MIN_VALUE; List ports = new ArrayList(2); for (int j = i + 1; j < names.size(); j++, i++) { name = names.get(j); value = values.get(j); if (CookieHeaderNames.DISCARD.equalsIgnoreCase(name)) { discard = true; } else if (CookieHeaderNames.SECURE.equalsIgnoreCase(name)) { secure = true; } else if (CookieHeaderNames.HTTPONLY.equalsIgnoreCase(name)) { httpOnly = true; } else if (CookieHeaderNames.COMMENT.equalsIgnoreCase(name)) { comment = value; } else if (CookieHeaderNames.COMMENTURL.equalsIgnoreCase(name)) { commentURL = value; } else if (CookieHeaderNames.DOMAIN.equalsIgnoreCase(name)) { domain = value; } else if (CookieHeaderNames.PATH.equalsIgnoreCase(name)) { path = value; } else if (CookieHeaderNames.EXPIRES.equalsIgnoreCase(name)) { try { long maxAgeMillis = HttpHeaderDateFormat.get().parse(value).getTime() - System.currentTimeMillis(); maxAge = (int) (maxAgeMillis / 1000) + (maxAgeMillis % 1000 != 0? 1 : 0); } catch (ParseException e) { // Ignore. } } else if (CookieHeaderNames.MAX_AGE.equalsIgnoreCase(name)) { maxAge = Integer.parseInt(value); } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) { version = Integer.parseInt(value); } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) { String[] portList = StringUtil.split(value, COMMA); for (String s1: portList) { try { ports.add(Integer.valueOf(s1)); } catch (NumberFormatException e) { // Ignore. } } } else { break; } } c.setVersion(version); c.setMaxAge(maxAge); c.setPath(path); c.setDomain(domain); c.setSecure(secure); c.setHttpOnly(httpOnly); if (version > 0) { c.setComment(comment); } if (version > 1) { c.setCommentUrl(commentURL); c.setPorts(ports); c.setDiscard(discard); } cookies.add(c); } return cookies; } private static void extractKeyValuePairs( final String header, final List names, final List values) { final int headerLen = header.length(); loop: for (int i = 0;;) { // Skip spaces and separators. for (;;) { if (i == headerLen) { break loop; } switch (header.charAt(i)) { case '\t': case '\n': case 0x0b: case '\f': case '\r': case ' ': case ',': case ';': i ++; continue; } break; } // Skip '$'. for (;;) { if (i == headerLen) { break loop; } if (header.charAt(i) == '$') { i ++; continue; } break; } String name; String value; if (i == headerLen) { name = null; value = null; } else { int newNameStart = i; keyValLoop: for (;;) { switch (header.charAt(i)) { case ';': // NAME; (no value till ';') name = header.substring(newNameStart, i); value = null; break keyValLoop; case '=': // NAME=VALUE name = header.substring(newNameStart, i); i ++; if (i == headerLen) { // NAME= (empty value, i.e. nothing after '=') value = ""; break keyValLoop; } int newValueStart = i; char c = header.charAt(i); if (c == '"' || c == '\'') { // NAME="VALUE" or NAME='VALUE' StringBuilder newValueBuf = new StringBuilder(header.length() - i); final char q = c; boolean hadBackslash = false; i ++; for (;;) { if (i == headerLen) { value = newValueBuf.toString(); break keyValLoop; } if (hadBackslash) { hadBackslash = false; c = header.charAt(i ++); switch (c) { case '\\': case '"': case '\'': // Escape last backslash. newValueBuf.setCharAt(newValueBuf.length() - 1, c); break; default: // Do not escape last backslash. newValueBuf.append(c); } } else { c = header.charAt(i ++); if (c == q) { value = newValueBuf.toString(); break keyValLoop; } newValueBuf.append(c); if (c == '\\') { hadBackslash = true; } } } } else { // NAME=VALUE; int semiPos = header.indexOf(';', i); if (semiPos > 0) { value = header.substring(newValueStart, semiPos); i = semiPos; } else { value = header.substring(newValueStart); i = headerLen; } } break keyValLoop; default: i ++; } if (i == headerLen) { // NAME (no value till the end of string) name = header.substring(newNameStart); value = null; break; } } } names.add(name); values.add(value); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/CookieEncoder.java000066400000000000000000000231361225554127700316310ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Date; import java.util.Set; import java.util.TreeSet; /** * Encodes {@link Cookie}s into an HTTP header value. This encoder can encode * the HTTP cookie version 0, 1, and 2. *

* This encoder is stateful. It maintains an internal data structure that * holds the {@link Cookie}s added by the {@link #addCookie(String, String)} * method. Once {@link #encode()} is called, all added {@link Cookie}s are * encoded into an HTTP header value and all {@link Cookie}s in the internal * data structure are removed so that the encoder can start over. *

 * // Client-side example
 * {@link HttpRequest} req = ...;
 * {@link CookieEncoder} encoder = new {@link CookieEncoder}(false);
 * encoder.addCookie("JSESSIONID", "1234");
 * res.setHeader("Cookie", encoder.encode());
 *
 * // Server-side example
 * {@link HttpResponse} res = ...;
 * {@link CookieEncoder} encoder = new {@link CookieEncoder}(true);
 * encoder.addCookie("JSESSIONID", "1234");
 * res.setHeader("Set-Cookie", encoder.encode());
 * 
* * @see CookieDecoder * * @apiviz.stereotype utility * @apiviz.has org.jboss.netty.handler.codec.http.Cookie oneway - - encodes */ public class CookieEncoder { private final Set cookies = new TreeSet(); private final boolean server; /** * Creates a new encoder. * * @param server {@code true} if and only if this encoder is supposed to * encode server-side cookies. {@code false} if and only if * this encoder is supposed to encode client-side cookies. */ public CookieEncoder(boolean server) { this.server = server; } /** * Adds a new {@link Cookie} created with the specified name and value to * this encoder. */ public void addCookie(String name, String value) { cookies.add(new DefaultCookie(name, value)); } /** * Adds the specified {@link Cookie} to this encoder. */ public void addCookie(Cookie cookie) { cookies.add(cookie); } /** * Encodes the {@link Cookie}s which were added by {@link #addCookie(Cookie)} * so far into an HTTP header value. If no {@link Cookie}s were added, * an empty string is returned. * * Be aware that calling this method will clear the content of the {@link CookieEncoder} */ public String encode() { String answer; if (server) { answer = encodeServerSide(); } else { answer = encodeClientSide(); } cookies.clear(); return answer; } private String encodeServerSide() { if (cookies.size() > 1) { throw new IllegalStateException( "encode() can encode only one cookie on server mode: " + cookies.size() + " cookies added"); } StringBuilder sb = new StringBuilder(); for (Cookie cookie: cookies) { add(sb, cookie.getName(), cookie.getValue()); if (cookie.getMaxAge() != Integer.MIN_VALUE) { if (cookie.getVersion() == 0) { addUnquoted(sb, CookieHeaderNames.EXPIRES, HttpHeaderDateFormat.get().format( new Date(System.currentTimeMillis() + cookie.getMaxAge() * 1000L))); } else { add(sb, CookieHeaderNames.MAX_AGE, cookie.getMaxAge()); } } if (cookie.getPath() != null) { if (cookie.getVersion() > 0) { add(sb, CookieHeaderNames.PATH, cookie.getPath()); } else { addUnquoted(sb, CookieHeaderNames.PATH, cookie.getPath()); } } if (cookie.getDomain() != null) { if (cookie.getVersion() > 0) { add(sb, CookieHeaderNames.DOMAIN, cookie.getDomain()); } else { addUnquoted(sb, CookieHeaderNames.DOMAIN, cookie.getDomain()); } } if (cookie.isSecure()) { sb.append(CookieHeaderNames.SECURE); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } if (cookie.isHttpOnly()) { sb.append(CookieHeaderNames.HTTPONLY); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } if (cookie.getVersion() >= 1) { if (cookie.getComment() != null) { add(sb, CookieHeaderNames.COMMENT, cookie.getComment()); } add(sb, CookieHeaderNames.VERSION, 1); if (cookie.getCommentUrl() != null) { addQuoted(sb, CookieHeaderNames.COMMENTURL, cookie.getCommentUrl()); } if (!cookie.getPorts().isEmpty()) { sb.append(CookieHeaderNames.PORT); sb.append((char) HttpConstants.EQUALS); sb.append((char) HttpConstants.DOUBLE_QUOTE); for (int port: cookie.getPorts()) { sb.append(port); sb.append((char) HttpConstants.COMMA); } sb.setCharAt(sb.length() - 1, (char) HttpConstants.DOUBLE_QUOTE); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } if (cookie.isDiscard()) { sb.append(CookieHeaderNames.DISCARD); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } } } if (sb.length() > 0) { sb.setLength(sb.length() - 2); } return sb.toString(); } private String encodeClientSide() { StringBuilder sb = new StringBuilder(); for (Cookie cookie: cookies) { if (cookie.getVersion() >= 1) { add(sb, '$' + CookieHeaderNames.VERSION, 1); } add(sb, cookie.getName(), cookie.getValue()); if (cookie.getPath() != null) { add(sb, '$' + CookieHeaderNames.PATH, cookie.getPath()); } if (cookie.getDomain() != null) { add(sb, '$' + CookieHeaderNames.DOMAIN, cookie.getDomain()); } if (cookie.getVersion() >= 1) { if (!cookie.getPorts().isEmpty()) { sb.append('$'); sb.append(CookieHeaderNames.PORT); sb.append((char) HttpConstants.EQUALS); sb.append((char) HttpConstants.DOUBLE_QUOTE); for (int port: cookie.getPorts()) { sb.append(port); sb.append((char) HttpConstants.COMMA); } sb.setCharAt(sb.length() - 1, (char) HttpConstants.DOUBLE_QUOTE); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } } } if (sb.length() > 0) { sb.setLength(sb.length() - 2); } return sb.toString(); } private static void add(StringBuilder sb, String name, String val) { if (val == null) { addQuoted(sb, name, ""); return; } for (int i = 0; i < val.length(); i ++) { char c = val.charAt(i); switch (c) { case '\t': case ' ': case '"': case '(': case ')': case ',': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '{': case '}': addQuoted(sb, name, val); return; } } addUnquoted(sb, name, val); } private static void addUnquoted(StringBuilder sb, String name, String val) { sb.append(name); sb.append((char) HttpConstants.EQUALS); sb.append(val); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } private static void addQuoted(StringBuilder sb, String name, String val) { if (val == null) { val = ""; } sb.append(name); sb.append((char) HttpConstants.EQUALS); sb.append((char) HttpConstants.DOUBLE_QUOTE); sb.append(val.replace("\\", "\\\\").replace("\"", "\\\"")); sb.append((char) HttpConstants.DOUBLE_QUOTE); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } private static void add(StringBuilder sb, String name, int val) { sb.append(name); sb.append((char) HttpConstants.EQUALS); sb.append(val); sb.append((char) HttpConstants.SEMICOLON); sb.append((char) HttpConstants.SP); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/CookieHeaderNames.java000066400000000000000000000023671225554127700324310ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; final class CookieHeaderNames { static final String PATH = "Path"; static final String EXPIRES = "Expires"; static final String MAX_AGE = "Max-Age"; static final String DOMAIN = "Domain"; static final String SECURE = "Secure"; static final String HTTPONLY = "HTTPOnly"; static final String COMMENT = "Comment"; static final String COMMENTURL = "CommentURL"; static final String DISCARD = "Discard"; static final String PORT = "Port"; static final String VERSION = "Version"; private CookieHeaderNames() { // Unused. } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/DefaultCookie.java000066400000000000000000000213031225554127700316300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Collections; import java.util.Set; import java.util.TreeSet; /** * The default {@link Cookie} implementation. */ public class DefaultCookie implements Cookie { private final String name; private String value; private String domain; private String path; private String comment; private String commentUrl; private boolean discard; private Set ports = Collections.emptySet(); private Set unmodifiablePorts = ports; private int maxAge = Integer.MIN_VALUE; private int version; private boolean secure; private boolean httpOnly; /** * Creates a new cookie with the specified name and value. */ public DefaultCookie(String name, String value) { if (name == null) { throw new NullPointerException("name"); } name = name.trim(); if (name.length() == 0) { throw new IllegalArgumentException("empty name"); } for (int i = 0; i < name.length(); i ++) { char c = name.charAt(i); if (c > 127) { throw new IllegalArgumentException( "name contains non-ascii character: " + name); } // Check prohibited characters. switch (c) { case '\t': case '\n': case 0x0b: case '\f': case '\r': case ' ': case ',': case ';': case '=': throw new IllegalArgumentException( "name contains one of the following prohibited characters: " + "=,; \\t\\r\\n\\v\\f: " + name); } } if (name.charAt(0) == '$') { throw new IllegalArgumentException("name starting with '$' not allowed: " + name); } this.name = name; setValue(value); } public String getName() { return name; } public String getValue() { return value; } public void setValue(String value) { if (value == null) { throw new NullPointerException("value"); } this.value = value; } public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = validateValue("domain", domain); } public String getPath() { return path; } public void setPath(String path) { this.path = validateValue("path", path); } public String getComment() { return comment; } public void setComment(String comment) { this.comment = validateValue("comment", comment); } public String getCommentUrl() { return commentUrl; } public void setCommentUrl(String commentUrl) { this.commentUrl = validateValue("commentUrl", commentUrl); } public boolean isDiscard() { return discard; } public void setDiscard(boolean discard) { this.discard = discard; } public Set getPorts() { if (unmodifiablePorts == null) { unmodifiablePorts = Collections.unmodifiableSet(ports); } return unmodifiablePorts; } public void setPorts(int... ports) { if (ports == null) { throw new NullPointerException("ports"); } int[] portsCopy = ports.clone(); if (portsCopy.length == 0) { unmodifiablePorts = this.ports = Collections.emptySet(); } else { Set newPorts = new TreeSet(); for (int p: portsCopy) { if (p <= 0 || p > 65535) { throw new IllegalArgumentException("port out of range: " + p); } newPorts.add(p); } this.ports = newPorts; unmodifiablePorts = null; } } public void setPorts(Iterable ports) { Set newPorts = new TreeSet(); for (int p: ports) { if (p <= 0 || p > 65535) { throw new IllegalArgumentException("port out of range: " + p); } newPorts.add(p); } if (newPorts.isEmpty()) { unmodifiablePorts = this.ports = Collections.emptySet(); } else { this.ports = newPorts; unmodifiablePorts = null; } } public int getMaxAge() { return maxAge; } public void setMaxAge(int maxAge) { this.maxAge = maxAge; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public boolean isSecure() { return secure; } public void setSecure(boolean secure) { this.secure = secure; } public boolean isHttpOnly() { return httpOnly; } public void setHttpOnly(boolean httpOnly) { this.httpOnly = httpOnly; } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof Cookie)) { return false; } Cookie that = (Cookie) o; if (!getName().equalsIgnoreCase(that.getName())) { return false; } if (getPath() == null) { if (that.getPath() != null) { return false; } } else if (that.getPath() == null) { return false; } else if (!getPath().equals(that.getPath())) { return false; } if (getDomain() == null) { if (that.getDomain() != null) { return false; } } else if (that.getDomain() == null) { return false; } else { return getDomain().equalsIgnoreCase(that.getDomain()); } return true; } public int compareTo(Cookie c) { int v; v = getName().compareToIgnoreCase(c.getName()); if (v != 0) { return v; } if (getPath() == null) { if (c.getPath() != null) { return -1; } } else if (c.getPath() == null) { return 1; } else { v = getPath().compareTo(c.getPath()); if (v != 0) { return v; } } if (getDomain() == null) { if (c.getDomain() != null) { return -1; } } else if (c.getDomain() == null) { return 1; } else { v = getDomain().compareToIgnoreCase(c.getDomain()); return v; } return 0; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getName()); buf.append('='); buf.append(getValue()); if (getDomain() != null) { buf.append(", domain="); buf.append(getDomain()); } if (getPath() != null) { buf.append(", path="); buf.append(getPath()); } if (getComment() != null) { buf.append(", comment="); buf.append(getComment()); } if (getMaxAge() >= 0) { buf.append(", maxAge="); buf.append(getMaxAge()); buf.append('s'); } if (isSecure()) { buf.append(", secure"); } if (isHttpOnly()) { buf.append(", HTTPOnly"); } return buf.toString(); } private static String validateValue(String name, String value) { if (value == null) { return null; } value = value.trim(); if (value.length() == 0) { return null; } for (int i = 0; i < value.length(); i ++) { char c = value.charAt(i); switch (c) { case '\r': case '\n': case '\f': case 0x0b: case ';': throw new IllegalArgumentException( name + " contains one of the following prohibited characters: " + ";\\r\\n\\f\\v (" + value + ')'); } } return value; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/DefaultHttpChunk.java000066400000000000000000000027451225554127700323400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; /** * The default {@link HttpChunk} implementation. */ public class DefaultHttpChunk implements HttpChunk { private ChannelBuffer content; private boolean last; /** * Creates a new instance with the specified chunk content. If an empty * buffer is specified, this chunk becomes the 'end of content' marker. */ public DefaultHttpChunk(ChannelBuffer content) { setContent(content); } public ChannelBuffer getContent() { return content; } public void setContent(ChannelBuffer content) { if (content == null) { throw new NullPointerException("content"); } last = !content.readable(); this.content = content; } public boolean isLast() { return last; } } DefaultHttpChunkTrailer.java000066400000000000000000000111311225554127700335710ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.internal.StringUtil; import java.util.List; import java.util.Map; import java.util.Set; /** * The default {@link HttpChunkTrailer} implementation. */ public class DefaultHttpChunkTrailer implements HttpChunkTrailer { private final HttpHeaders trailingHeaders = new TrailingHeaders(true); public boolean isLast() { return true; } @Deprecated public void addHeader(final String name, final Object value) { trailingHeaders.add(name, value); } @Deprecated public void setHeader(final String name, final Object value) { trailingHeaders.set(name, value); } @Deprecated public void setHeader(final String name, final Iterable values) { trailingHeaders.set(name, values); } @Deprecated public void removeHeader(final String name) { trailingHeaders.remove(name); } @Deprecated public void clearHeaders() { trailingHeaders.clear(); } @Deprecated public String getHeader(final String name) { return trailingHeaders.get(name); } @Deprecated public List getHeaders(final String name) { return trailingHeaders.getAll(name); } @Deprecated public List> getHeaders() { return trailingHeaders.entries(); } @Deprecated public boolean containsHeader(final String name) { return trailingHeaders.contains(name); } @Deprecated public Set getHeaderNames() { return trailingHeaders.names(); } public ChannelBuffer getContent() { return ChannelBuffers.EMPTY_BUFFER; } public void setContent(ChannelBuffer content) { throw new IllegalStateException("read-only"); } public HttpHeaders trailingHeaders() { return trailingHeaders; } @Override public String toString() { StringBuilder buf = new StringBuilder(super.toString()); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } private void appendHeaders(StringBuilder buf) { for (Map.Entry e: trailingHeaders()) { buf.append(e.getKey()); buf.append(": "); buf.append(e.getValue()); buf.append(StringUtil.NEWLINE); } } private static final class TrailingHeaders extends DefaultHttpHeaders { TrailingHeaders(boolean validateHeaders) { super(validateHeaders); } @Override public HttpHeaders add(String name, Object value) { if (validate) { validateName(name); } return super.add(name, value); } @Override public HttpHeaders add(String name, Iterable values) { if (validate) { validateName(name); } return super.add(name, values); } @Override public HttpHeaders set(String name, Iterable values) { if (validate) { validateName(name); } return super.set(name, values); } @Override public HttpHeaders set(String name, Object value) { if (validate) { validateName(name); } return super.set(name, value); } private static void validateName(String name) { if (name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) || name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) || name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) { throw new IllegalArgumentException( "prohibited trailing header: " + name); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/DefaultHttpHeaders.java000066400000000000000000000312371225554127700326410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; public class DefaultHttpHeaders extends HttpHeaders { private static final int BUCKET_SIZE = 17; private static final Set KNOWN_NAMES = createSet(Names.class); private static final Set KNOWN_VALUES = createSet(Values.class); private static Set createSet(Class clazz) { Set set = new HashSet(); Field[] fields = clazz.getDeclaredFields(); for (Field f: fields) { int m = f.getModifiers(); if (Modifier.isPublic(m) && Modifier.isStatic(m) && Modifier.isFinal(m) && f.getType().isAssignableFrom(String.class)) { try { set.add((String) f.get(null)); } catch (Throwable cause) { // ignore } } } return set; } private static int hash(String name, boolean validate) { int h = 0; for (int i = name.length() - 1; i >= 0; i --) { char c = name.charAt(i); if (validate) { valideHeaderNameChar(c); } c = toLowerCase(c); h = 31 * h + c; } if (h > 0) { return h; } else if (h == Integer.MIN_VALUE) { return Integer.MAX_VALUE; } else { return -h; } } private static boolean eq(String name1, String name2) { if (name1 == name2) { // check for object equality as the user may reuse our static fields in HttpHeaders.Names return true; } int nameLen = name1.length(); if (nameLen != name2.length()) { return false; } for (int i = nameLen - 1; i >= 0; i --) { char c1 = name1.charAt(i); char c2 = name2.charAt(i); if (c1 != c2) { if (toLowerCase(c1) != toLowerCase(c2)) { return false; } } } return true; } private static char toLowerCase(char c) { if (c >= 'A' && c <= 'Z') { c += 32; } return c; } private static int index(int hash) { return hash % BUCKET_SIZE; } private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE]; private final HeaderEntry head = new HeaderEntry(-1, null, null); protected final boolean validate; public DefaultHttpHeaders() { this(true); } public DefaultHttpHeaders(boolean validate) { head.before = head.after = head; this.validate = validate; } void validateHeaderValue0(String headerValue) { if (KNOWN_VALUES.contains(headerValue)) { return; } validateHeaderValue(headerValue); } @Override public HttpHeaders add(final String name, final Object value) { String strVal = toString(value); boolean validateName = false; if (validate) { validateHeaderValue0(strVal); validateName = !KNOWN_NAMES.contains(name); } int h = hash(name, validateName); int i = index(h); add0(h, i, name, strVal); return this; } @Override public HttpHeaders add(String name, Iterable values) { boolean validateName = false; if (validate) { validateName = !KNOWN_NAMES.contains(name); } int h = hash(name, validateName); int i = index(h); for (Object v: values) { String vstr = toString(v); if (validate) { validateHeaderValue0(vstr); } add0(h, i, name, vstr); } return this; } private void add0(int h, int i, final String name, final String value) { // Update the hash table. HeaderEntry e = entries[i]; HeaderEntry newEntry; entries[i] = newEntry = new HeaderEntry(h, name, value); newEntry.next = e; // Update the linked list. newEntry.addBefore(head); } @Override public HttpHeaders remove(final String name) { if (name == null) { throw new NullPointerException("name"); } int h = hash(name, false); int i = index(h); remove0(h, i, name); return this; } private void remove0(int h, int i, String name) { HeaderEntry e = entries[i]; if (e == null) { return; } for (;;) { if (e.hash == h && eq(name, e.key)) { e.remove(); HeaderEntry next = e.next; if (next != null) { entries[i] = next; e = next; } else { entries[i] = null; return; } } else { break; } } for (;;) { HeaderEntry next = e.next; if (next == null) { break; } if (next.hash == h && eq(name, next.key)) { e.next = next.next; next.remove(); } else { e = next; } } } @Override public HttpHeaders set(final String name, final Object value) { String strVal = toString(value); boolean validateName = false; if (validate) { validateHeaderValue0(strVal); validateName = !KNOWN_NAMES.contains(name); } int h = hash(name, validateName); int i = index(h); remove0(h, i, name); add0(h, i, name, strVal); return this; } @Override public HttpHeaders set(final String name, final Iterable values) { if (values == null) { throw new NullPointerException("values"); } boolean validateName = false; if (validate) { validateName = !KNOWN_NAMES.contains(name); } int h = hash(name, validateName); int i = index(h); remove0(h, i, name); for (Object v: values) { if (v == null) { break; } String strVal = toString(v); if (validate) { validateHeaderValue0(strVal); } add0(h, i, name, strVal); } return this; } @Override public HttpHeaders clear() { Arrays.fill(entries, null); head.before = head.after = head; return this; } @Override public String get(final String name) { return get(name, false); } private String get(final String name, boolean last) { if (name == null) { throw new NullPointerException("name"); } int h = hash(name, false); int i = index(h); HeaderEntry e = entries[i]; String value = null; // loop until the first header was found while (e != null) { if (e.hash == h && eq(name, e.key)) { value = e.value; if (last) { break; } } e = e.next; } return value; } @Override public List getAll(final String name) { if (name == null) { throw new NullPointerException("name"); } LinkedList values = new LinkedList(); int h = hash(name, false); int i = index(h); HeaderEntry e = entries[i]; while (e != null) { if (e.hash == h && eq(name, e.key)) { values.addFirst(e.value); } e = e.next; } return values; } @Override public List> entries() { List> all = new LinkedList>(); HeaderEntry e = head.after; while (e != head) { all.add(e); e = e.after; } return all; } @Override public Iterator> iterator() { return new HeaderIterator(); } @Override public boolean contains(String name) { return get(name, true) != null; } @Override public boolean isEmpty() { return head == head.after; } @Override public boolean contains(String name, String value, boolean ignoreCaseValue) { if (name == null) { throw new NullPointerException("name"); } int h = hash(name, false); int i = index(h); HeaderEntry e = entries[i]; while (e != null) { if (e.hash == h && eq(name, e.key)) { if (ignoreCaseValue) { if (e.value.equalsIgnoreCase(value)) { return true; } } else { if (e.value.equals(value)) { return true; } } } e = e.next; } return false; } @Override public Set names() { Set names = new LinkedHashSet(); HeaderEntry e = head.after; while (e != head) { names.add(e.key); e = e.after; } return names; } private static String toString(Object value) { if (value == null) { return null; } if (value instanceof String) { return (String) value; } if (value instanceof Number) { return value.toString(); } if (value instanceof Date) { return HttpHeaderDateFormat.get().format((Date) value); } if (value instanceof Calendar) { return HttpHeaderDateFormat.get().format(((Calendar) value).getTime()); } return value.toString(); } private final class HeaderIterator implements Iterator> { private HeaderEntry current = head; @Override public boolean hasNext() { return current.after != head; } @Override public Entry next() { current = current.after; if (current == head) { throw new NoSuchElementException(); } return current; } @Override public void remove() { throw new UnsupportedOperationException(); } } private final class HeaderEntry implements Map.Entry { final int hash; final String key; String value; HeaderEntry next; HeaderEntry before, after; HeaderEntry(int hash, String key, String value) { this.hash = hash; this.key = key; this.value = value; } void remove() { before.after = after; after.before = before; } void addBefore(HeaderEntry e) { after = e; before = e.before; before.after = this; after.before = this; } @Override public String getKey() { return key; } @Override public String getValue() { return value; } @Override public String setValue(String value) { if (value == null) { throw new NullPointerException("value"); } if (validate) { validateHeaderValue0(value); } String oldValue = this.value; this.value = value; return oldValue; } @Override public String toString() { return key + '=' + value; } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/DefaultHttpMessage.java000066400000000000000000000106011225554127700326420ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.internal.StringUtil; import java.util.List; import java.util.Map; import java.util.Set; /** * The default {@link HttpMessage} implementation. */ public class DefaultHttpMessage implements HttpMessage { private final HttpHeaders headers = new DefaultHttpHeaders(true); private HttpVersion version; private ChannelBuffer content = ChannelBuffers.EMPTY_BUFFER; private boolean chunked; /** * Creates a new instance. */ protected DefaultHttpMessage(final HttpVersion version) { setProtocolVersion(version); } public HttpHeaders headers() { return headers; } @Deprecated public void addHeader(final String name, final Object value) { headers.add(name, value); } @Deprecated public void setHeader(final String name, final Object value) { headers.set(name, value); } @Deprecated public void setHeader(final String name, final Iterable values) { headers.set(name, values); } @Deprecated public void removeHeader(final String name) { headers.remove(name); } public boolean isChunked() { if (chunked) { return true; } else { return HttpCodecUtil.isTransferEncodingChunked(this); } } public void setChunked(boolean chunked) { this.chunked = chunked; if (chunked) { setContent(ChannelBuffers.EMPTY_BUFFER); } } @Deprecated public void clearHeaders() { headers.clear(); } public void setContent(ChannelBuffer content) { if (content == null) { content = ChannelBuffers.EMPTY_BUFFER; } if (content.readable() && isChunked()) { throw new IllegalArgumentException( "non-empty content disallowed if this.chunked == true"); } this.content = content; } @Deprecated public String getHeader(final String name) { return headers.get(name); } @Deprecated public List getHeaders(final String name) { return headers.getAll(name); } @Deprecated public List> getHeaders() { return headers.entries(); } @Deprecated public boolean containsHeader(final String name) { return headers.contains(name); } @Deprecated public Set getHeaderNames() { return headers.names(); } public HttpVersion getProtocolVersion() { return version; } public void setProtocolVersion(HttpVersion version) { if (version == null) { throw new NullPointerException("version"); } this.version = version; } public ChannelBuffer getContent() { return content; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(version: "); buf.append(getProtocolVersion().getText()); buf.append(", keepAlive: "); buf.append(HttpHeaders.isKeepAlive(this)); buf.append(", chunked: "); buf.append(isChunked()); buf.append(')'); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } void appendHeaders(StringBuilder buf) { for (Map.Entry e: headers()) { buf.append(e.getKey()); buf.append(": "); buf.append(e.getValue()); buf.append(StringUtil.NEWLINE); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/DefaultHttpRequest.java000066400000000000000000000046141225554127700327150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link HttpRequest} implementation. */ public class DefaultHttpRequest extends DefaultHttpMessage implements HttpRequest { private HttpMethod method; private String uri; /** * Creates a new instance. * * @param httpVersion the HTTP version of the request * @param method the HTTP method of the request * @param uri the URI or path of the request */ public DefaultHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri) { super(httpVersion); setMethod(method); setUri(uri); } public HttpMethod getMethod() { return method; } public void setMethod(HttpMethod method) { if (method == null) { throw new NullPointerException("method"); } this.method = method; } public String getUri() { return uri; } public void setUri(String uri) { if (uri == null) { throw new NullPointerException("uri"); } this.uri = uri; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(chunked: "); buf.append(isChunked()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getMethod().toString()); buf.append(' '); buf.append(getUri()); buf.append(' '); buf.append(getProtocolVersion().getText()); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/DefaultHttpResponse.java000066400000000000000000000040421225554127700330560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link HttpResponse} implementation. */ public class DefaultHttpResponse extends DefaultHttpMessage implements HttpResponse { private HttpResponseStatus status; /** * Creates a new instance. * * @param version the HTTP version of this response * @param status the status of this response */ public DefaultHttpResponse(HttpVersion version, HttpResponseStatus status) { super(version); setStatus(status); } public HttpResponseStatus getStatus() { return status; } public void setStatus(HttpResponseStatus status) { if (status == null) { throw new NullPointerException("status"); } this.status = status; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(chunked: "); buf.append(isChunked()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getProtocolVersion().getText()); buf.append(' '); buf.append(getStatus().toString()); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpChunk.java000066400000000000000000000071211225554127700310240ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelPipeline; /** * An HTTP chunk which is used for HTTP chunked transfer-encoding. * {@link HttpMessageDecoder} generates {@link HttpChunk} after * {@link HttpMessage} when the content is large or the encoding of the content * is 'chunked. If you prefer not to receive {@link HttpChunk} in your handler, * please {@link HttpChunkAggregator} after {@link HttpMessageDecoder} in the * {@link ChannelPipeline}. * @apiviz.landmark */ public interface HttpChunk { /** * The 'end of content' marker in chunked encoding. */ HttpChunkTrailer LAST_CHUNK = new HttpChunkTrailer() { public ChannelBuffer getContent() { return ChannelBuffers.EMPTY_BUFFER; } public void setContent(ChannelBuffer content) { throw new IllegalStateException("read-only"); } public boolean isLast() { return true; } @Deprecated public void addHeader(String name, Object value) { throw new IllegalStateException("read-only"); } @Deprecated public void clearHeaders() { // NOOP } @Deprecated public boolean containsHeader(String name) { return false; } @Deprecated public String getHeader(String name) { return null; } @Deprecated public Set getHeaderNames() { return Collections.emptySet(); } @Deprecated public List getHeaders(String name) { return Collections.emptyList(); } @Deprecated public List> getHeaders() { return Collections.emptyList(); } @Deprecated public void removeHeader(String name) { // NOOP } @Deprecated public void setHeader(String name, Object value) { throw new IllegalStateException("read-only"); } @Deprecated public void setHeader(String name, Iterable values) { throw new IllegalStateException("read-only"); } public HttpHeaders trailingHeaders() { return HttpHeaders.EMPTY_HEADERS; } }; /** * Returns {@code true} if and only if this chunk is the 'end of content' * marker. */ boolean isLast(); /** * Returns the content of this chunk. If this is the 'end of content' * marker, {@link ChannelBuffers#EMPTY_BUFFER} will be returned. */ ChannelBuffer getContent(); /** * Sets the content of this chunk. If an empty buffer is specified, * this chunk becomes the 'end of content' marker. */ void setContent(ChannelBuffer content); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpChunkAggregator.java000066400000000000000000000231111225554127700330240ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.jboss.netty.channel.Channels.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.*; import java.util.List; import java.util.Map.Entry; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.CompositeChannelBuffer; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.util.CharsetUtil; /** * A {@link ChannelHandler} that aggregates an {@link HttpMessage} * and its following {@link HttpChunk}s into a single {@link HttpMessage} with * no following {@link HttpChunk}s. It is useful when you don't want to take * care of HTTP messages whose transfer encoding is 'chunked'. Insert this * handler after {@link HttpMessageDecoder} in the {@link ChannelPipeline}: *
 * {@link ChannelPipeline} p = ...;
 * ...
 * p.addLast("decoder", new {@link HttpRequestDecoder}());
 * p.addLast("aggregator", new {@link HttpChunkAggregator}(1048576));
 * ...
 * p.addLast("encoder", new {@link HttpResponseEncoder}());
 * p.addLast("handler", new HttpRequestHandler());
 * 
* @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.http.HttpChunk oneway - - filters out */ public class HttpChunkAggregator extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler { public static final int DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS = 1024; private static final ChannelBuffer CONTINUE = ChannelBuffers.copiedBuffer( "HTTP/1.1 100 Continue\r\n\r\n", CharsetUtil.US_ASCII); private final int maxContentLength; private HttpMessage currentMessage; private boolean tooLongFrameFound; private ChannelHandlerContext ctx; private int maxCumulationBufferComponents = DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS; /** * Creates a new instance. * * @param maxContentLength * the maximum length of the aggregated content. * If the length of the aggregated content exceeds this value, * a {@link TooLongFrameException} will be raised. */ public HttpChunkAggregator(int maxContentLength) { if (maxContentLength <= 0) { throw new IllegalArgumentException( "maxContentLength must be a positive integer: " + maxContentLength); } this.maxContentLength = maxContentLength; } /** * Returns the maximum number of components in the cumulation buffer. If the number of * the components in the cumulation buffer exceeds this value, the components of the * cumulation buffer are consolidated into a single component, involving memory copies. * The default value of this property is {@link #DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS}. */ public final int getMaxCumulationBufferComponents() { return maxCumulationBufferComponents; } /** * Sets the maximum number of components in the cumulation buffer. If the number of * the components in the cumulation buffer exceeds this value, the components of the * cumulation buffer are consolidated into a single component, involving memory copies. * The default value of this property is {@link #DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS} * and its minimum allowed value is {@code 2}. */ public final void setMaxCumulationBufferComponents(int maxCumulationBufferComponents) { if (maxCumulationBufferComponents < 2) { throw new IllegalArgumentException( "maxCumulationBufferComponents: " + maxCumulationBufferComponents + " (expected: >= 2)"); } if (ctx == null) { this.maxCumulationBufferComponents = maxCumulationBufferComponents; } else { throw new IllegalStateException( "decoder properties cannot be changed once the decoder is added to a pipeline."); } } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); HttpMessage currentMessage = this.currentMessage; if (msg instanceof HttpMessage) { HttpMessage m = (HttpMessage) msg; tooLongFrameFound = false; // Handle the 'Expect: 100-continue' header if necessary. // TODO: Respond with 413 Request Entity Too Large // and discard the traffic or close the connection. // No need to notify the upstream handlers - just log. // If decoding a response, just throw an exception. if (is100ContinueExpected(m)) { write(ctx, succeededFuture(ctx.getChannel()), CONTINUE.duplicate()); } if (m.isChunked()) { // A chunked message - remove 'Transfer-Encoding' header, // initialize the cumulative buffer, and wait for incoming chunks. HttpCodecUtil.removeTransferEncodingChunked(m); m.setChunked(false); this.currentMessage = m; } else { // Not a chunked message - pass through. this.currentMessage = null; ctx.sendUpstream(e); } } else if (msg instanceof HttpChunk) { // Sanity check if (currentMessage == null) { throw new IllegalStateException( "received " + HttpChunk.class.getSimpleName() + " without " + HttpMessage.class.getSimpleName()); } HttpChunk chunk = (HttpChunk) msg; if (tooLongFrameFound) { if (chunk.isLast()) { this.currentMessage = null; } return; } // Merge the received chunk into the content of the current message. ChannelBuffer content = currentMessage.getContent(); if (content.readableBytes() > maxContentLength - chunk.getContent().readableBytes()) { tooLongFrameFound = true; throw new TooLongFrameException( "HTTP content length exceeded " + maxContentLength + " bytes."); } // Append the content of the chunk appendToCumulation(chunk.getContent()); if (chunk.isLast()) { this.currentMessage = null; // Merge trailing headers into the message. if (chunk instanceof HttpChunkTrailer) { HttpChunkTrailer trailer = (HttpChunkTrailer) chunk; for (Entry header: trailer.trailingHeaders()) { currentMessage.headers().set(header.getKey(), header.getValue()); } } // Set the 'Content-Length' header. currentMessage.headers().set( HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(content.readableBytes())); // All done - generate the event. fireMessageReceived(ctx, currentMessage, e.getRemoteAddress()); } } else { // Neither HttpMessage or HttpChunk ctx.sendUpstream(e); } } protected void appendToCumulation(ChannelBuffer input) { ChannelBuffer cumulation = currentMessage.getContent(); if (cumulation instanceof CompositeChannelBuffer) { // Make sure the resulting cumulation buffer has no more than the configured components. CompositeChannelBuffer composite = (CompositeChannelBuffer) cumulation; if (composite.numComponents() >= maxCumulationBufferComponents) { currentMessage.setContent(ChannelBuffers.wrappedBuffer(composite.copy(), input)); } else { List decomposed = composite.decompose(0, composite.readableBytes()); ChannelBuffer[] buffers = decomposed.toArray(new ChannelBuffer[decomposed.size() + 1]); buffers[buffers.length - 1] = input; currentMessage.setContent(ChannelBuffers.wrappedBuffer(buffers)); } } else { currentMessage.setContent(ChannelBuffers.wrappedBuffer(cumulation, input)); } } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // noop } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // noop } public void afterRemove(ChannelHandlerContext ctx) throws Exception { // noop } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpChunkTrailer.java000066400000000000000000000047541225554127700323600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.List; import java.util.Map; import java.util.Set; /** * The last {@link HttpChunk} which has trailing headers. */ public interface HttpChunkTrailer extends HttpChunk { /** * Always returns {@code true}. */ boolean isLast(); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated String getHeader(String name); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated List getHeaders(String name); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated List> getHeaders(); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated boolean containsHeader(String name); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated Set getHeaderNames(); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated void addHeader(String name, Object value); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated void setHeader(String name, Object value); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated void setHeader(String name, Iterable values); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated void removeHeader(String name); /** * @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead. */ @Deprecated void clearHeaders(); /** * Returns the trialing headers of this trailer. */ HttpHeaders trailingHeaders(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpClientCodec.java000066400000000000000000000220401225554127700321250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.handler.codec.PrematureChannelClosureException; /** * A combination of {@link HttpRequestEncoder} and {@link HttpResponseDecoder} * which enables easier client side HTTP implementation. {@link HttpClientCodec} * provides additional state management for HEAD and CONNECT * requests, which {@link HttpResponseDecoder} lacks. Please refer to * {@link HttpResponseDecoder} to learn what additional state management needs * to be done for HEAD and CONNECT and why * {@link HttpResponseDecoder} can not handle it by itself. * * If the {@link Channel} gets closed and there are requests missing for a response * a {@link PrematureChannelClosureException} is thrown. * * @see HttpServerCodec * * @apiviz.has org.jboss.netty.handler.codec.http.HttpResponseDecoder * @apiviz.has org.jboss.netty.handler.codec.http.HttpRequestEncoder */ public class HttpClientCodec implements ChannelUpstreamHandler, ChannelDownstreamHandler { /** A queue that is used for correlating a request and a response. */ final Queue queue = new ConcurrentLinkedQueue(); /** If true, decoding stops (i.e. pass-through) */ volatile boolean done; private final HttpRequestEncoder encoder = new Encoder(); private final HttpResponseDecoder decoder; private final AtomicLong requestResponseCounter = new AtomicLong(0); private final boolean failOnMissingResponse; /** * Creates a new instance with the default decoder options * ({@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxChunkSize (8192)}). * */ public HttpClientCodec() { this(4096, 8192, 8192, false); } /** * Creates a new instance with the specified decoder options. */ public HttpClientCodec( int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { this(maxInitialLineLength, maxHeaderSize, maxChunkSize, false); } /** * Creates a new instance with the specified decoder options. */ public HttpClientCodec( int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean failOnMissingResponse) { decoder = new Decoder(maxInitialLineLength, maxHeaderSize, maxChunkSize); this.failOnMissingResponse = failOnMissingResponse; } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { decoder.handleUpstream(ctx, e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { encoder.handleDownstream(ctx, e); } private final class Encoder extends HttpRequestEncoder { Encoder() { } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof HttpRequest && !done) { queue.offer(((HttpRequest) msg).getMethod()); } Object obj = super.encode(ctx, channel, msg); if (failOnMissingResponse) { // check if the request is chunked if so do not increment if (msg instanceof HttpRequest && !((HttpRequest) msg).isChunked()) { requestResponseCounter.incrementAndGet(); } else if (msg instanceof HttpChunk && ((HttpChunk) msg).isLast()) { // increment as its the last chunk requestResponseCounter.incrementAndGet(); } } return obj; } } private final class Decoder extends HttpResponseDecoder { Decoder(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { super(maxInitialLineLength, maxHeaderSize, maxChunkSize); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { if (done) { int readable = actualReadableBytes(); if (readable == 0) { return null; } return buffer.readBytes(readable); } else { Object msg = super.decode(ctx, channel, buffer, state); if (failOnMissingResponse) { decrement(msg); } return msg; } } private void decrement(Object msg) { if (msg == null) { return; } // check if its a HttpMessage and its not chunked if (msg instanceof HttpMessage && !((HttpMessage) msg).isChunked()) { requestResponseCounter.decrementAndGet(); } else if (msg instanceof HttpChunk && ((HttpChunk) msg).isLast()) { requestResponseCounter.decrementAndGet(); } else if (msg instanceof Object[]) { // we just decrement it here as we only use this if the end of the chunk is reached // It would be more safe to check all the objects in the array but would also be slower requestResponseCounter.decrementAndGet(); } } @Override protected boolean isContentAlwaysEmpty(HttpMessage msg) { final int statusCode = ((HttpResponse) msg).getStatus().getCode(); if (statusCode == 100) { // 100-continue response should be excluded from paired comparison. return true; } // Get the method of the HTTP request that corresponds to the // current response. HttpMethod method = queue.poll(); char firstChar = method.getName().charAt(0); switch (firstChar) { case 'H': // According to 4.3, RFC2616: // All responses to the HEAD request method MUST NOT include a // message-body, even though the presence of entity-header fields // might lead one to believe they do. if (HttpMethod.HEAD.equals(method)) { return true; // The following code was inserted to work around the servers // that behave incorrectly. It has been commented out // because it does not work with well behaving servers. // Please note, even if the 'Transfer-Encoding: chunked' // header exists in the HEAD response, the response should // have absolutely no content. // //// Interesting edge case: //// Some poorly implemented servers will send a zero-byte //// chunk if Transfer-Encoding of the response is 'chunked'. //// //// return !msg.isChunked(); } break; case 'C': // Successful CONNECT request results in a response with empty body. if (statusCode == 200) { if (HttpMethod.CONNECT.equals(method)) { // Proxy connection established - Not HTTP anymore. done = true; queue.clear(); return true; } } break; } return super.isContentAlwaysEmpty(msg); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelClosed(ctx, e); if (failOnMissingResponse) { long missingResponses = requestResponseCounter.get(); if (missingResponses > 0) { throw new PrematureChannelClosureException( "Channel closed but still missing " + missingResponses + " response(s)"); } } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpCodecUtil.java000066400000000000000000000114771225554127700316400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Iterator; import java.util.List; final class HttpCodecUtil { static void validateHeaderName(String name) { if (name == null) { throw new NullPointerException("name"); } for (int i = 0; i < name.length(); i ++) { char c = name.charAt(i); if (c > 127) { throw new IllegalArgumentException( "name contains non-ascii character: " + name); } // Check prohibited characters. switch (c) { case '\t': case '\n': case 0x0b: case '\f': case '\r': case ' ': case ',': case ':': case ';': case '=': throw new IllegalArgumentException( "name contains one of the following prohibited characters: " + "=,;: \\t\\r\\n\\v\\f: " + name); } } } static void validateHeaderValue(String value) { if (value == null) { throw new NullPointerException("value"); } // 0 - the previous character was neither CR nor LF // 1 - the previous character was CR // 2 - the previous character was LF int state = 0; for (int i = 0; i < value.length(); i ++) { char c = value.charAt(i); // Check the absolutely prohibited characters. switch (c) { case 0x0b: // Vertical tab throw new IllegalArgumentException( "value contains a prohibited character '\\v': " + value); case '\f': throw new IllegalArgumentException( "value contains a prohibited character '\\f': " + value); } // Check the CRLF (HT | SP) pattern switch (state) { case 0: switch (c) { case '\r': state = 1; break; case '\n': state = 2; break; } break; case 1: switch (c) { case '\n': state = 2; break; default: throw new IllegalArgumentException( "Only '\\n' is allowed after '\\r': " + value); } break; case 2: switch (c) { case '\t': case ' ': state = 0; break; default: throw new IllegalArgumentException( "Only ' ' and '\\t' are allowed after '\\n': " + value); } } } if (state != 0) { throw new IllegalArgumentException( "value must not end with '\\r' or '\\n':" + value); } } static boolean isTransferEncodingChunked(HttpMessage m) { List chunked = m.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING); if (chunked.isEmpty()) { return false; } for (String v: chunked) { if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) { return true; } } return false; } static void removeTransferEncodingChunked(HttpMessage m) { List values = m.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING); if (values.isEmpty()) { return; } Iterator valuesIt = values.iterator(); while (valuesIt.hasNext()) { String value = valuesIt.next(); if (value.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) { valuesIt.remove(); } } if (values.isEmpty()) { m.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); } else { m.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, values); } } static boolean isContentLengthSet(HttpMessage m) { List contentLength = m.headers().getAll(HttpHeaders.Names.CONTENT_LENGTH); return !contentLength.isEmpty(); } private HttpCodecUtil() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpConstants.java000066400000000000000000000032261225554127700317320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.nio.charset.Charset; import org.jboss.netty.util.CharsetUtil; public final class HttpConstants { /** * Horizontal space */ public static final byte SP = 32; /** * Horizontal tab */ public static final byte HT = 9; /** * Carriage return */ public static final byte CR = 13; /** * Equals '=' */ public static final byte EQUALS = 61; /** * Line feed character */ public static final byte LF = 10; /** * Colon ':' */ public static final byte COLON = 58; /** * Semicolon ';' */ public static final byte SEMICOLON = 59; /** * Comma ',' */ public static final byte COMMA = 44; /** * Double quote '"' */ public static final byte DOUBLE_QUOTE = '"'; /** * Default character set (UTF-8) */ public static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8; private HttpConstants() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpContentCompressor.java000066400000000000000000000152051225554127700334450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.compression.JdkZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibWrapper; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.jboss.netty.util.internal.DetectionUtil; import org.jboss.netty.util.internal.StringUtil; /** * Compresses an {@link HttpMessage} and an {@link HttpChunk} in {@code gzip} or * {@code deflate} encoding while respecting the {@code "Accept-Encoding"} header. * If there is no matching encoding, no compression is done. For more * information on how this handler modifies the message, please refer to * {@link HttpContentEncoder}. */ public class HttpContentCompressor extends HttpContentEncoder { private final int compressionLevel; private final int windowBits; private final int memLevel; /** * Creates a new handler with the default compression level (6), * default window size (15) and default memory level (8). */ public HttpContentCompressor() { this(6); } /** * Creates a new handler with the specified compression level, default * window size (15) and default memory level (8). * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. */ public HttpContentCompressor(int compressionLevel) { this(compressionLevel, 15, 8); } /** * Creates a new handler with the specified compression level, window size, * and memory level.. * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default * compression level is {@code 6}. * @param windowBits * The base two logarithm of the size of the history buffer. The * value should be in the range {@code 9} to {@code 15} inclusive. * Larger values result in better compression at the expense of * memory usage. The default value is {@code 15}. * @param memLevel * How much memory should be allocated for the internal compression * state. {@code 1} uses minimum memory and {@code 9} uses maximum * memory. Larger values result in better and faster compression * at the expense of memory usage. The default value is {@code 8} */ public HttpContentCompressor(int compressionLevel, int windowBits, int memLevel) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } if (windowBits < 9 || windowBits > 15) { throw new IllegalArgumentException( "windowBits: " + windowBits + " (expected: 9-15)"); } if (memLevel < 1 || memLevel > 9) { throw new IllegalArgumentException( "memLevel: " + memLevel + " (expected: 1-9)"); } this.compressionLevel = compressionLevel; this.windowBits = windowBits; this.memLevel = memLevel; } @Override protected EncoderEmbedder newContentEncoder( HttpMessage msg, String acceptEncoding) throws Exception { String contentEncoding = msg.headers().get(HttpHeaders.Names.CONTENT_ENCODING); if (contentEncoding != null && !HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) { // Encoded already. return null; } ZlibWrapper wrapper = determineWrapper(acceptEncoding); if (wrapper == null) { return null; } if (DetectionUtil.javaVersion() >= 7) { return new EncoderEmbedder( new JdkZlibEncoder(wrapper, compressionLevel)); } else { return new EncoderEmbedder( new ZlibEncoder(wrapper, compressionLevel, windowBits, memLevel)); } } @Override protected String getTargetContentEncoding(String acceptEncoding) throws Exception { ZlibWrapper wrapper = determineWrapper(acceptEncoding); if (wrapper == null) { return null; } switch (wrapper) { case GZIP: return "gzip"; case ZLIB: return "deflate"; default: throw new Error(); } } private static ZlibWrapper determineWrapper(String acceptEncoding) { float starQ = -1.0f; float gzipQ = -1.0f; float deflateQ = -1.0f; for (String encoding: StringUtil.split(acceptEncoding, ',')) { float q = 1.0f; int equalsPos = encoding.indexOf('='); if (equalsPos != -1) { try { q = Float.valueOf(encoding.substring(equalsPos + 1)); } catch (NumberFormatException e) { // Ignore encoding q = 0.0f; } } if (encoding.indexOf('*') >= 0) { starQ = q; } else if (encoding.contains("gzip") && q > gzipQ) { gzipQ = q; } else if (encoding.contains("deflate") && q > deflateQ) { deflateQ = q; } } if (gzipQ > 0.0f || deflateQ > 0.0f) { if (gzipQ >= deflateQ) { return ZlibWrapper.GZIP; } else { return ZlibWrapper.ZLIB; } } if (starQ > 0.0f) { if (gzipQ == -1.0f) { return ZlibWrapper.GZIP; } if (deflateQ == -1.0f) { return ZlibWrapper.ZLIB; } } return null; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpContentDecoder.java000066400000000000000000000207251225554127700326610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; /** * Decodes the content of the received {@link HttpRequest} and {@link HttpChunk}. * The original content is replaced with the new content decoded by the * {@link DecoderEmbedder}, which is created by {@link #newContentDecoder(String)}. * Once decoding is finished, the value of the 'Content-Encoding' * header is set to the target content encoding, as returned by {@link #getTargetContentEncoding(String)}. * Also, the 'Content-Length' header is updated to the length of the * decoded content. If the content encoding of the original is not supported * by the decoder, {@link #newContentDecoder(String)} should return {@code null} * so that no decoding occurs (i.e. pass-through). *

* Please note that this is an abstract class. You have to extend this class * and implement {@link #newContentDecoder(String)} properly to make this class * functional. For example, refer to the source code of {@link HttpContentDecompressor}. *

* This handler must be placed after {@link HttpMessageDecoder} in the pipeline * so that this handler can intercept HTTP requests after {@link HttpMessageDecoder} * converts {@link ChannelBuffer}s into HTTP requests. */ public abstract class HttpContentDecoder extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler { private DecoderEmbedder decoder; /** * Creates a new instance. */ protected HttpContentDecoder() { } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().getCode() == 100) { // 100-continue response must be passed through. ctx.sendUpstream(e); } else if (msg instanceof HttpMessage) { HttpMessage m = (HttpMessage) msg; // Clean-up the previous decoder if not cleaned up correctly. finishDecode(); // Determine the content encoding. String contentEncoding = m.headers().get(HttpHeaders.Names.CONTENT_ENCODING); if (contentEncoding != null) { contentEncoding = contentEncoding.trim(); } else { contentEncoding = HttpHeaders.Values.IDENTITY; } boolean hasContent = m.isChunked() || m.getContent().readable(); if (hasContent && (decoder = newContentDecoder(contentEncoding)) != null) { // Decode the content and remove or replace the existing headers // so that the message looks like a decoded message. String targetContentEncoding = getTargetContentEncoding(contentEncoding); if (HttpHeaders.Values.IDENTITY.equals(targetContentEncoding)) { // Do NOT set the 'Content-Encoding' header if the target encoding is 'identity' // as per: http://tools.ietf.org/html/rfc2616#section-14.11 m.headers().remove(HttpHeaders.Names.CONTENT_ENCODING); } else { m.headers().set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding); } if (!m.isChunked()) { ChannelBuffer content = m.getContent(); // Decode the content content = ChannelBuffers.wrappedBuffer( decode(content), finishDecode()); // Replace the content. m.setContent(content); if (m.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) { m.headers().set( HttpHeaders.Names.CONTENT_LENGTH, Integer.toString(content.readableBytes())); } } } // Because HttpMessage is a mutable object, we can simply forward the received event. ctx.sendUpstream(e); } else if (msg instanceof HttpChunk) { HttpChunk c = (HttpChunk) msg; ChannelBuffer content = c.getContent(); // Decode the chunk if necessary. if (decoder != null) { if (!c.isLast()) { content = decode(content); if (content.readable()) { c.setContent(content); ctx.sendUpstream(e); } } else { ChannelBuffer lastProduct = finishDecode(); // Generate an additional chunk if the decoder produced // the last product on closure, if (lastProduct.readable()) { Channels.fireMessageReceived( ctx, new DefaultHttpChunk(lastProduct), e.getRemoteAddress()); } // Emit the last chunk. ctx.sendUpstream(e); } } else { ctx.sendUpstream(e); } } else { ctx.sendUpstream(e); } } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Clean-up the previous decoder if not cleaned up correctly. finishDecode(); super.channelClosed(ctx, e); } /** * Returns a new {@link DecoderEmbedder} that decodes the HTTP message * content encoded in the specified contentEncoding. * * @param contentEncoding the value of the {@code "Content-Encoding"} header * @return a new {@link DecoderEmbedder} if the specified encoding is supported. * {@code null} otherwise (alternatively, you can throw an exception * to block unknown encoding). */ protected abstract DecoderEmbedder newContentDecoder(String contentEncoding) throws Exception; /** * Returns the expected content encoding of the decoded content. * This method returns {@code "identity"} by default, which is the case for * most decoders. * * @param contentEncoding the value of the {@code "Content-Encoding"} header * @return the expected content encoding of the new content */ protected String getTargetContentEncoding(String contentEncoding) throws Exception { return HttpHeaders.Values.IDENTITY; } private ChannelBuffer decode(ChannelBuffer buf) { decoder.offer(buf); return ChannelBuffers.wrappedBuffer(decoder.pollAll(new ChannelBuffer[decoder.size()])); } private ChannelBuffer finishDecode() { if (decoder == null) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer result; if (decoder.finish()) { result = ChannelBuffers.wrappedBuffer(decoder.pollAll(new ChannelBuffer[decoder.size()])); } else { result = ChannelBuffers.EMPTY_BUFFER; } decoder = null; return result; } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { // NOOP } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // NOOP } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // NOOP } public void afterRemove(ChannelHandlerContext ctx) throws Exception { finishDecode(); } } HttpContentDecompressor.java000066400000000000000000000036061225554127700337010ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.compression.ZlibDecoder; import org.jboss.netty.handler.codec.compression.ZlibWrapper; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; /** * Decompresses an {@link HttpMessage} and an {@link HttpChunk} compressed in * {@code gzip} or {@code deflate} encoding. For more information on how this * handler modifies the message, please refer to {@link HttpContentDecoder}. */ public class HttpContentDecompressor extends HttpContentDecoder { @Override protected DecoderEmbedder newContentDecoder(String contentEncoding) throws Exception { if ("gzip".equalsIgnoreCase(contentEncoding) || "x-gzip".equalsIgnoreCase(contentEncoding)) { return new DecoderEmbedder(new ZlibDecoder(ZlibWrapper.GZIP)); } if ("deflate".equalsIgnoreCase(contentEncoding) || "x-deflate".equalsIgnoreCase(contentEncoding)) { // To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly. return new DecoderEmbedder(new ZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); } // 'identity' or unsupported return null; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpContentEncoder.java000066400000000000000000000223301225554127700326650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; /** * Encodes the content of the outbound {@link HttpResponse} and {@link HttpChunk}. * The original content is replaced with the new content encoded by the * {@link EncoderEmbedder}, which is created by {@link #newContentEncoder(HttpMessage, String)}. * Once encoding is finished, the value of the 'Content-Encoding' header * is set to the target content encoding, as returned by {@link #getTargetContentEncoding(String)}. * Also, the 'Content-Length' header is updated to the length of the * encoded content. If there is no supported encoding in the * corresponding {@link HttpRequest}'s {@code "Accept-Encoding"} header, * {@link #newContentEncoder(HttpMessage, String)} should return {@code null} so that no * encoding occurs (i.e. pass-through). *

* Please note that this is an abstract class. You have to extend this class * and implement {@link #newContentEncoder(HttpMessage, String)} and {@link #getTargetContentEncoding(String)} * properly to make this class functional. For example, refer to the source * code of {@link HttpContentCompressor}. *

* This handler must be placed after {@link HttpMessageEncoder} in the pipeline * so that this handler can intercept HTTP responses before {@link HttpMessageEncoder} * converts them into {@link ChannelBuffer}s. */ public abstract class HttpContentEncoder extends SimpleChannelHandler implements LifeCycleAwareChannelHandler { private final Queue acceptEncodingQueue = new ConcurrentLinkedQueue(); private volatile EncoderEmbedder encoder; /** * Creates a new instance. */ protected HttpContentEncoder() { } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (!(msg instanceof HttpMessage)) { ctx.sendUpstream(e); return; } HttpMessage m = (HttpMessage) msg; String acceptedEncoding = m.headers().get(HttpHeaders.Names.ACCEPT_ENCODING); if (acceptedEncoding == null) { acceptedEncoding = HttpHeaders.Values.IDENTITY; } boolean offered = acceptEncodingQueue.offer(acceptedEncoding); assert offered; ctx.sendUpstream(e); } @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().getCode() == 100) { // 100-continue response must be passed through. ctx.sendDownstream(e); } else if (msg instanceof HttpMessage) { HttpMessage m = (HttpMessage) msg; // Clean-up the previous encoder if not cleaned up correctly. finishEncode(); String acceptEncoding = acceptEncodingQueue.poll(); if (acceptEncoding == null) { throw new IllegalStateException("cannot send more responses than requests"); } String contentEncoding = m.headers().get(HttpHeaders.Names.CONTENT_ENCODING); if (contentEncoding != null && !HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) { // Content-Encoding is set already and it is not 'identity'. ctx.sendDownstream(e); } else { // Determine the content encoding. boolean hasContent = m.isChunked() || m.getContent().readable(); if (hasContent && (encoder = newContentEncoder(m, acceptEncoding)) != null) { // Encode the content and remove or replace the existing headers // so that the message looks like a decoded message. m.headers().set( HttpHeaders.Names.CONTENT_ENCODING, getTargetContentEncoding(acceptEncoding)); if (!m.isChunked()) { ChannelBuffer content = m.getContent(); // Encode the content. content = ChannelBuffers.wrappedBuffer( encode(content), finishEncode()); // Replace the content. m.setContent(content); if (m.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) { m.headers().set( HttpHeaders.Names.CONTENT_LENGTH, Integer.toString(content.readableBytes())); } } } // Because HttpMessage is a mutable object, we can simply forward the write request. ctx.sendDownstream(e); } } else if (msg instanceof HttpChunk) { HttpChunk c = (HttpChunk) msg; ChannelBuffer content = c.getContent(); // Encode the chunk if necessary. if (encoder != null) { if (!c.isLast()) { content = encode(content); if (content.readable()) { c.setContent(content); ctx.sendDownstream(e); } } else { ChannelBuffer lastProduct = finishEncode(); // Generate an additional chunk if the decoder produced // the last product on closure, if (lastProduct.readable()) { Channels.write( ctx, Channels.succeededFuture(e.getChannel()), new DefaultHttpChunk(lastProduct), e.getRemoteAddress()); } // Emit the last chunk. ctx.sendDownstream(e); } } else { ctx.sendDownstream(e); } } else { ctx.sendDownstream(e); } } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Clean-up the previous encoder if not cleaned up correctly. finishEncode(); super.channelClosed(ctx, e); } /** * Returns a new {@link EncoderEmbedder} that encodes the HTTP message * content. * * @param acceptEncoding * the value of the {@code "Accept-Encoding"} header * * @return a new {@link EncoderEmbedder} if there is a supported encoding * in {@code acceptEncoding}. {@code null} otherwise. */ protected abstract EncoderEmbedder newContentEncoder( HttpMessage msg, String acceptEncoding) throws Exception; /** * Returns the expected content encoding of the encoded content. * * @param acceptEncoding the value of the {@code "Accept-Encoding"} header * @return the expected content encoding of the new content */ protected abstract String getTargetContentEncoding(String acceptEncoding) throws Exception; private ChannelBuffer encode(ChannelBuffer buf) { encoder.offer(buf); return ChannelBuffers.wrappedBuffer(encoder.pollAll(new ChannelBuffer[encoder.size()])); } private ChannelBuffer finishEncode() { if (encoder == null) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer result; if (encoder.finish()) { result = ChannelBuffers.wrappedBuffer(encoder.pollAll(new ChannelBuffer[encoder.size()])); } else { result = ChannelBuffers.EMPTY_BUFFER; } encoder = null; return result; } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { // NOOP } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // NOOP } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // NOOP } public void afterRemove(ChannelHandlerContext ctx) throws Exception { finishEncode(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpHeaderDateFormat.java000066400000000000000000000063671225554127700331260ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; /** * This DateFormat decodes 3 formats of {@link Date}, but only encodes the one, * the first: *

    *
  • Sun, 06 Nov 1994 08:49:37 GMT: standard specification, the only one with * valid generation
  • *
  • Sun, 06 Nov 1994 08:49:37 GMT: obsolete specification
  • *
  • Sun Nov 6 08:49:37 1994: obsolete specification
  • *
*/ final class HttpHeaderDateFormat extends SimpleDateFormat { private static final long serialVersionUID = -925286159755905325L; private final SimpleDateFormat format1 = new HttpHeaderDateFormatObsolete1(); private final SimpleDateFormat format2 = new HttpHeaderDateFormatObsolete2(); private static final ThreadLocal FORMAT_THREAD_LOCAL = new ThreadLocal() { @Override protected HttpHeaderDateFormat initialValue() { return new HttpHeaderDateFormat(); } }; public static HttpHeaderDateFormat get() { return FORMAT_THREAD_LOCAL.get(); } /** * Standard date format

* Sun, 06 Nov 1994 08:49:37 GMT -> E, d MMM yyyy HH:mm:ss z */ private HttpHeaderDateFormat() { super("E, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); setTimeZone(TimeZone.getTimeZone("GMT")); } @Override public Date parse(String text, ParsePosition pos) { Date date = super.parse(text, pos); if (date == null) { date = format1.parse(text, pos); } if (date == null) { date = format2.parse(text, pos); } return date; } /** * First obsolete format

* Sunday, 06-Nov-94 08:49:37 GMT -> E, d-MMM-y HH:mm:ss z */ private static final class HttpHeaderDateFormatObsolete1 extends SimpleDateFormat { private static final long serialVersionUID = -3178072504225114298L; HttpHeaderDateFormatObsolete1() { super("E, dd-MMM-yy HH:mm:ss z", Locale.ENGLISH); setTimeZone(TimeZone.getTimeZone("GMT")); } } /** * Second obsolete format *

* Sun Nov 6 08:49:37 1994 -> EEE, MMM d HH:mm:ss yyyy */ private static final class HttpHeaderDateFormatObsolete2 extends SimpleDateFormat { private static final long serialVersionUID = 3010674519968303714L; HttpHeaderDateFormatObsolete2() { super("E MMM d HH:mm:ss yyyy", Locale.ENGLISH); setTimeZone(TimeZone.getTimeZone("GMT")); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpHeaders.java000066400000000000000000001304221225554127700313300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.text.ParseException; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Provides the constants for the standard HTTP header names and values and * commonly used utility methods that accesses an {@link HttpMessage}. */ public abstract class HttpHeaders implements Iterable> { public static final HttpHeaders EMPTY_HEADERS = new HttpHeaders() { @Override public String get(String name) { return null; } @Override public List getAll(String name) { return Collections.emptyList(); } @Override public List> entries() { return Collections.emptyList(); } @Override public boolean contains(String name) { return false; } @Override public boolean isEmpty() { return true; } @Override public Set names() { return Collections.emptySet(); } @Override public HttpHeaders add(String name, Object value) { throw new UnsupportedOperationException("read only"); } @Override public HttpHeaders add(String name, Iterable values) { throw new UnsupportedOperationException("read only"); } @Override public HttpHeaders set(String name, Object value) { throw new UnsupportedOperationException("read only"); } @Override public HttpHeaders set(String name, Iterable values) { throw new UnsupportedOperationException("read only"); } @Override public HttpHeaders remove(String name) { throw new UnsupportedOperationException("read only"); } @Override public HttpHeaders clear() { throw new UnsupportedOperationException("read only"); } @Override public Iterator> iterator() { return entries().iterator(); } }; /** * Standard HTTP header names. */ public static final class Names { /** * {@code "Accept"} */ public static final String ACCEPT = "Accept"; /** * {@code "Accept-Charset"} */ public static final String ACCEPT_CHARSET = "Accept-Charset"; /** * {@code "Accept-Encoding"} */ public static final String ACCEPT_ENCODING = "Accept-Encoding"; /** * {@code "Accept-Language"} */ public static final String ACCEPT_LANGUAGE = "Accept-Language"; /** * {@code "Accept-Ranges"} */ public static final String ACCEPT_RANGES = "Accept-Ranges"; /** * {@code "Accept-Patch"} */ public static final String ACCEPT_PATCH = "Accept-Patch"; /** * {@code "Access-Control-Allow-Credentials"} */ public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; /** * {@code "Access-Control-Allow-Headers"} */ public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; /** * {@code "Access-Control-Allow-Methods"} */ public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; /** * {@code "Access-Control-Allow-Origin"} */ public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; /** * {@code "Access-Control-Expose-Headers"} */ public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; /** * {@code "Access-Control-Max-Age"} */ public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; /** * {@code "Access-Control-Request-Headers"} */ public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; /** * {@code "Access-Control-Request-Method"} */ public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method"; /** * {@code "Age"} */ public static final String AGE = "Age"; /** * {@code "Allow"} */ public static final String ALLOW = "Allow"; /** * {@code "Authorization"} */ public static final String AUTHORIZATION = "Authorization"; /** * {@code "Cache-Control"} */ public static final String CACHE_CONTROL = "Cache-Control"; /** * {@code "Connection"} */ public static final String CONNECTION = "Connection"; /** * {@code "Content-Base"} */ public static final String CONTENT_BASE = "Content-Base"; /** * {@code "Content-Encoding"} */ public static final String CONTENT_ENCODING = "Content-Encoding"; /** * {@code "Content-Language"} */ public static final String CONTENT_LANGUAGE = "Content-Language"; /** * {@code "Content-Length"} */ public static final String CONTENT_LENGTH = "Content-Length"; /** * {@code "Content-Location"} */ public static final String CONTENT_LOCATION = "Content-Location"; /** * {@code "Content-Transfer-Encoding"} */ public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; /** * {@code "Content-MD5"} */ public static final String CONTENT_MD5 = "Content-MD5"; /** * {@code "Content-Range"} */ public static final String CONTENT_RANGE = "Content-Range"; /** * {@code "Content-Type"} */ public static final String CONTENT_TYPE = "Content-Type"; /** * {@code "Cookie"} */ public static final String COOKIE = "Cookie"; /** * {@code "Date"} */ public static final String DATE = "Date"; /** * {@code "ETag"} */ public static final String ETAG = "ETag"; /** * {@code "Expect"} */ public static final String EXPECT = "Expect"; /** * {@code "Expires"} */ public static final String EXPIRES = "Expires"; /** * {@code "From"} */ public static final String FROM = "From"; /** * {@code "Host"} */ public static final String HOST = "Host"; /** * {@code "If-Match"} */ public static final String IF_MATCH = "If-Match"; /** * {@code "If-Modified-Since"} */ public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; /** * {@code "If-None-Match"} */ public static final String IF_NONE_MATCH = "If-None-Match"; /** * {@code "If-Range"} */ public static final String IF_RANGE = "If-Range"; /** * {@code "If-Unmodified-Since"} */ public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; /** * {@code "Last-Modified"} */ public static final String LAST_MODIFIED = "Last-Modified"; /** * {@code "Location"} */ public static final String LOCATION = "Location"; /** * {@code "Max-Forwards"} */ public static final String MAX_FORWARDS = "Max-Forwards"; /** * {@code "Origin"} */ public static final String ORIGIN = "Origin"; /** * {@code "Pragma"} */ public static final String PRAGMA = "Pragma"; /** * {@code "Proxy-Authenticate"} */ public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate"; /** * {@code "Proxy-Authorization"} */ public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; /** * {@code "Range"} */ public static final String RANGE = "Range"; /** * {@code "Referer"} */ public static final String REFERER = "Referer"; /** * {@code "Retry-After"} */ public static final String RETRY_AFTER = "Retry-After"; /** * {@code "Sec-WebSocket-Key1"} */ public static final String SEC_WEBSOCKET_KEY1 = "Sec-WebSocket-Key1"; /** * {@code "Sec-WebSocket-Key2"} */ public static final String SEC_WEBSOCKET_KEY2 = "Sec-WebSocket-Key2"; /** * {@code "Sec-WebSocket-Location"} */ public static final String SEC_WEBSOCKET_LOCATION = "Sec-WebSocket-Location"; /** * {@code "Sec-WebSocket-Origin"} */ public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin"; /** * {@code "Sec-WebSocket-Protocol"} */ public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol"; /** * {@code "Sec-WebSocket-Version"} */ public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version"; /** * {@code "Sec-WebSocket-Key"} */ public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key"; /** * {@code "Sec-WebSocket-Accept"} */ public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept"; /** * {@code "Server"} */ public static final String SERVER = "Server"; /** * {@code "Set-Cookie"} */ public static final String SET_COOKIE = "Set-Cookie"; /** * {@code "Set-Cookie2"} */ public static final String SET_COOKIE2 = "Set-Cookie2"; /** * {@code "TE"} */ public static final String TE = "TE"; /** * {@code "Trailer"} */ public static final String TRAILER = "Trailer"; /** * {@code "Transfer-Encoding"} */ public static final String TRANSFER_ENCODING = "Transfer-Encoding"; /** * {@code "Upgrade"} */ public static final String UPGRADE = "Upgrade"; /** * {@code "User-Agent"} */ public static final String USER_AGENT = "User-Agent"; /** * {@code "Vary"} */ public static final String VARY = "Vary"; /** * {@code "Via"} */ public static final String VIA = "Via"; /** * {@code "Warning"} */ public static final String WARNING = "Warning"; /** * {@code "WebSocket-Location"} */ public static final String WEBSOCKET_LOCATION = "WebSocket-Location"; /** * {@code "WebSocket-Origin"} */ public static final String WEBSOCKET_ORIGIN = "WebSocket-Origin"; /** * {@code "WebSocket-Protocol"} */ public static final String WEBSOCKET_PROTOCOL = "WebSocket-Protocol"; /** * {@code "WWW-Authenticate"} */ public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; private Names() { } } /** * Standard HTTP header values. */ public static final class Values { /** * {@code "application/x-www-form-urlencoded"} */ public static final String APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; /** * {@code "base64"} */ public static final String BASE64 = "base64"; /** * {@code "binary"} */ public static final String BINARY = "binary"; /** * {@code "boundary"} */ public static final String BOUNDARY = "boundary"; /** * {@code "bytes"} */ public static final String BYTES = "bytes"; /** * {@code "charset"} */ public static final String CHARSET = "charset"; /** * {@code "chunked"} */ public static final String CHUNKED = "chunked"; /** * {@code "close"} */ public static final String CLOSE = "close"; /** * {@code "compress"} */ public static final String COMPRESS = "compress"; /** * {@code "100-continue"} */ public static final String CONTINUE = "100-continue"; /** * {@code "deflate"} */ public static final String DEFLATE = "deflate"; /** * {@code "gzip"} */ public static final String GZIP = "gzip"; /** * {@code "identity"} */ public static final String IDENTITY = "identity"; /** * {@code "keep-alive"} */ public static final String KEEP_ALIVE = "keep-alive"; /** * {@code "max-age"} */ public static final String MAX_AGE = "max-age"; /** * {@code "max-stale"} */ public static final String MAX_STALE = "max-stale"; /** * {@code "min-fresh"} */ public static final String MIN_FRESH = "min-fresh"; /** * {@code "multipart/form-data"} */ public static final String MULTIPART_FORM_DATA = "multipart/form-data"; /** * {@code "must-revalidate"} */ public static final String MUST_REVALIDATE = "must-revalidate"; /** * {@code "no-cache"} */ public static final String NO_CACHE = "no-cache"; /** * {@code "no-store"} */ public static final String NO_STORE = "no-store"; /** * {@code "no-transform"} */ public static final String NO_TRANSFORM = "no-transform"; /** * {@code "none"} */ public static final String NONE = "none"; /** * {@code "only-if-cached"} */ public static final String ONLY_IF_CACHED = "only-if-cached"; /** * {@code "private"} */ public static final String PRIVATE = "private"; /** * {@code "proxy-revalidate"} */ public static final String PROXY_REVALIDATE = "proxy-revalidate"; /** * {@code "public"} */ public static final String PUBLIC = "public"; /** * {@code "quoted-printable"} */ public static final String QUOTED_PRINTABLE = "quoted-printable"; /** * {@code "s-maxage"} */ public static final String S_MAXAGE = "s-maxage"; /** * {@code "trailers"} */ public static final String TRAILERS = "trailers"; /** * {@code "Upgrade"} */ public static final String UPGRADE = "Upgrade"; /** * {@code "WebSocket"} */ public static final String WEBSOCKET = "WebSocket"; private Values() { } } /** * Returns {@code true} if and only if the connection can remain open and * thus 'kept alive'. This methods respects the value of the * {@code "Connection"} header first and then the return value of * {@link HttpVersion#isKeepAliveDefault()}. */ public static boolean isKeepAlive(HttpMessage message) { String connection = message.headers().get(Names.CONNECTION); boolean close = Values.CLOSE.equalsIgnoreCase(connection); if (close) { return false; } if (message.getProtocolVersion().isKeepAliveDefault()) { return !close; } else { return Values.KEEP_ALIVE.equalsIgnoreCase(connection); } } /** * Sets the value of the {@code "Connection"} header depending on the * protocol version of the specified message. This method sets or removes * the {@code "Connection"} header depending on what the default keep alive * mode of the message's protocol version is, as specified by * {@link HttpVersion#isKeepAliveDefault()}. *

    *
  • If the connection is kept alive by default: *
      *
    • set to {@code "close"} if {@code keepAlive} is {@code false}.
    • *
    • remove otherwise.
    • *
  • *
  • If the connection is closed by default: *
      *
    • set to {@code "keep-alive"} if {@code keepAlive} is {@code true}.
    • *
    • remove otherwise.
    • *
  • *
*/ public static void setKeepAlive(HttpMessage message, boolean keepAlive) { HttpHeaders h = message.headers(); if (message.getProtocolVersion().isKeepAliveDefault()) { if (keepAlive) { h.remove(Names.CONNECTION); } else { h.set(Names.CONNECTION, Values.CLOSE); } } else { if (keepAlive) { h.set(Names.CONNECTION, Values.KEEP_ALIVE); } else { h.remove(Names.CONNECTION); } } } /** * Returns the header value with the specified header name. If there are * more than one header value for the specified header name, the first * value is returned. * * @return the header value or {@code null} if there is no such header */ public static String getHeader(HttpMessage message, String name) { return message.headers().get(name); } /** * Returns the header value with the specified header name. If there are * more than one header value for the specified header name, the first * value is returned. * * @return the header value or the {@code defaultValue} if there is no such * header */ public static String getHeader(HttpMessage message, String name, String defaultValue) { String value = message.headers().get(name); if (value == null) { return defaultValue; } return value; } /** * Sets a new header with the specified name and value. If there is an * existing header with the same name, the existing header is removed. * If the specified value is not a {@link String}, it is converted into a * {@link String} by {@link Object#toString()}, except for {@link Date} * and {@link Calendar} which are formatted to the date format defined in * RFC2616. */ public static void setHeader(HttpMessage message, String name, Object value) { message.headers().set(name, value); } /** * Sets a new header with the specified name and values. If there is an * existing header with the same name, the existing header is removed. * This getMethod can be represented approximately as the following code: *
     * removeHeader(message, name);
     * for (Object v: values) {
     *     if (v == null) {
     *         break;
     *     }
     *     addHeader(message, name, v);
     * }
     * 
*/ public static void setHeader(HttpMessage message, String name, Iterable values) { message.headers().set(name, values); } /** * Adds a new header with the specified name and value. * If the specified value is not a {@link String}, it is converted into a * {@link String} by {@link Object#toString()}, except for {@link Date} * and {@link Calendar} which are formatted to the date format defined in * RFC2616. */ public static void addHeader(HttpMessage message, String name, Object value) { message.headers().add(name, value); } /** * Removes the header with the specified name. */ public static void removeHeader(HttpMessage message, String name) { message.headers().remove(name); } /** * Removes all headers from the specified message. */ public static void clearHeaders(HttpMessage message) { message.headers().clear(); } /** * Returns the integer header value with the specified header name. If * there are more than one header value for the specified header name, the * first value is returned. * * @return the header value * @throws NumberFormatException * if there is no such header or the header value is not a number */ public static int getIntHeader(HttpMessage message, String name) { String value = getHeader(message, name); if (value == null) { throw new NumberFormatException("header not found: " + name); } return Integer.parseInt(value); } /** * Returns the integer header value with the specified header name. If * there are more than one header value for the specified header name, the * first value is returned. * * @return the header value or the {@code defaultValue} if there is no such * header or the header value is not a number */ public static int getIntHeader(HttpMessage message, String name, int defaultValue) { String value = getHeader(message, name); if (value == null) { return defaultValue; } try { return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } /** * Sets a new integer header with the specified name and value. If there * is an existing header with the same name, the existing header is removed. */ public static void setIntHeader(HttpMessage message, String name, int value) { message.headers().set(name, value); } /** * Sets a new integer header with the specified name and values. If there * is an existing header with the same name, the existing header is removed. */ public static void setIntHeader(HttpMessage message, String name, Iterable values) { message.headers().set(name, values); } /** * Adds a new integer header with the specified name and value. */ public static void addIntHeader(HttpMessage message, String name, int value) { message.headers().add(name, value); } /** * Returns the date header value with the specified header name. If * there are more than one header value for the specified header name, the * first value is returned. * * @return the header value * @throws ParseException * if there is no such header or the header value is not a formatted date */ public static Date getDateHeader(HttpMessage message, String name) throws ParseException { String value = getHeader(message, name); if (value == null) { throw new ParseException("header not found: " + name, 0); } return HttpHeaderDateFormat.get().parse(value); } /** * Returns the date header value with the specified header name. If * there are more than one header value for the specified header name, the * first value is returned. * * @return the header value or the {@code defaultValue} if there is no such * header or the header value is not a formatted date */ public static Date getDateHeader(HttpMessage message, String name, Date defaultValue) { final String value = getHeader(message, name); if (value == null) { return defaultValue; } try { return HttpHeaderDateFormat.get().parse(value); } catch (ParseException e) { return defaultValue; } } /** * Sets a new date header with the specified name and value. If there * is an existing header with the same name, the existing header is removed. * The specified value is formatted as defined in * RFC2616 */ public static void setDateHeader(HttpMessage message, String name, Date value) { if (value != null) { message.headers().set(name, HttpHeaderDateFormat.get().format(value)); } else { message.headers().set(name, null); } } /** * Sets a new date header with the specified name and values. If there * is an existing header with the same name, the existing header is removed. * The specified values are formatted as defined in * RFC2616 */ public static void setDateHeader(HttpMessage message, String name, Iterable values) { message.headers().set(name, values); } /** * Adds a new date header with the specified name and value. The specified * value is formatted as defined in * RFC2616 */ public static void addDateHeader(HttpMessage message, String name, Date value) { message.headers().add(name, value); } /** * Returns the length of the content. Please note that this value is * not retrieved from {@link HttpMessage#getContent()} but from the * {@code "Content-Length"} header, and thus they are independent from each * other. * * @return the content length * * @throws NumberFormatException * if the message does not have the {@code "Content-Length"} header * or its value is not a number */ public static long getContentLength(HttpMessage message) { String value = getHeader(message, Names.CONTENT_LENGTH); if (value != null) { return Long.parseLong(value); } // We know the content length if it's a Web Socket message even if // Content-Length header is missing. long webSocketContentLength = getWebSocketContentLength(message); if (webSocketContentLength >= 0) { return webSocketContentLength; } // Otherwise we don't. throw new NumberFormatException("header not found: " + Names.CONTENT_LENGTH); } /** * Returns the length of the content. Please note that this value is * not retrieved from {@link HttpMessage#getContent()} but from the * {@code "Content-Length"} header, and thus they are independent from each * other. * * @return the content length or {@code defaultValue} if this message does * not have the {@code "Content-Length"} header or its value is not * a number */ public static long getContentLength(HttpMessage message, long defaultValue) { String contentLength = message.headers().get(Names.CONTENT_LENGTH); if (contentLength != null) { try { return Long.parseLong(contentLength); } catch (NumberFormatException e) { return defaultValue; } } // We know the content length if it's a Web Socket message even if // Content-Length header is missing. long webSocketContentLength = getWebSocketContentLength(message); if (webSocketContentLength >= 0) { return webSocketContentLength; } // Otherwise we don't. return defaultValue; } /** * Returns the content length of the specified web socket message. If the * specified message is not a web socket message, {@code -1} is returned. */ private static int getWebSocketContentLength(HttpMessage message) { // WebSockset messages have constant content-lengths. HttpHeaders h = message.headers(); if (message instanceof HttpRequest) { HttpRequest req = (HttpRequest) message; if (HttpMethod.GET.equals(req.getMethod()) && h.contains(Names.SEC_WEBSOCKET_KEY1) && h.contains(Names.SEC_WEBSOCKET_KEY2)) { return 8; } } else if (message instanceof HttpResponse) { HttpResponse res = (HttpResponse) message; if (res.getStatus().getCode() == 101 && h.contains(Names.SEC_WEBSOCKET_ORIGIN) && h.contains(Names.SEC_WEBSOCKET_LOCATION)) { return 16; } } // Not a web socket message return -1; } /** * Sets the {@code "Content-Length"} header. */ public static void setContentLength(HttpMessage message, long length) { message.headers().set(Names.CONTENT_LENGTH, length); } /** * Returns the value of the {@code "Host"} header. */ public static String getHost(HttpMessage message) { return message.headers().get(Names.HOST); } /** * Returns the value of the {@code "Host"} header. If there is no such * header, the {@code defaultValue} is returned. */ public static String getHost(HttpMessage message, String defaultValue) { return getHeader(message, Names.HOST, defaultValue); } /** * Sets the {@code "Host"} header. */ public static void setHost(HttpMessage message, String value) { message.headers().set(Names.HOST, value); } /** * Returns the value of the {@code "Date"} header. * * @throws ParseException * if there is no such header or the header value is not a formatted date */ public static Date getDate(HttpMessage message) throws ParseException { return getDateHeader(message, Names.DATE); } /** * Returns the value of the {@code "Date"} header. If there is no such * header or the header is not a formatted date, the {@code defaultValue} * is returned. */ public static Date getDate(HttpMessage message, Date defaultValue) { return getDateHeader(message, Names.DATE, defaultValue); } /** * Sets the {@code "Date"} header. */ public static void setDate(HttpMessage message, Date value) { if (value != null) { message.headers().set(Names.DATE, HttpHeaderDateFormat.get().format(value)); } else { message.headers().set(Names.DATE, null); } } /** * Returns {@code true} if and only if the specified message contains the * {@code "Expect: 100-continue"} header. */ public static boolean is100ContinueExpected(HttpMessage message) { // Expect: 100-continue is for requests only. if (!(message instanceof HttpRequest)) { return false; } // It works only on HTTP/1.1 or later. if (message.getProtocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) { return false; } // In most cases, there will be one or zero 'Expect' header. String value = message.headers().get(Names.EXPECT); if (value == null) { return false; } if (Values.CONTINUE.equalsIgnoreCase(value)) { return true; } // Multiple 'Expect' headers. Search through them. return message.headers().contains(Names.EXPECT, Values.CONTINUE, true); } /** * Sets the {@code "Expect: 100-continue"} header to the specified message. * If there is any existing {@code "Expect"} header, they are replaced with * the new one. */ public static void set100ContinueExpected(HttpMessage message) { set100ContinueExpected(message, true); } /** * Sets or removes the {@code "Expect: 100-continue"} header to / from the * specified message. If the specified {@code value} is {@code true}, * the {@code "Expect: 100-continue"} header is set and all other previous * {@code "Expect"} headers are removed. Otherwise, all {@code "Expect"} * headers are removed completely. */ public static void set100ContinueExpected(HttpMessage message, boolean set) { if (set) { message.headers().set(Names.EXPECT, Values.CONTINUE); } else { message.headers().remove(Names.EXPECT); } } /** * Validates the name of a header * * @param headerName The header name being validated */ static void validateHeaderName(String headerName) { //Check to see if the name is null if (headerName == null) { throw new NullPointerException("Header names cannot be null"); } //Go through each of the characters in the name for (int index = 0; index < headerName.length(); index ++) { //Actually get the character char character = headerName.charAt(index); valideHeaderNameChar(character); } } static void valideHeaderNameChar(char c) { //Check to see if the character is not an ASCII character if (c > 127) { throw new IllegalArgumentException( "Header name cannot contain non-ASCII characters: " + c); } //Check for prohibited characters. switch (c) { case '\t': case '\n': case 0x0b: case '\f': case '\r': case ' ': case ',': case ':': case ';': case '=': throw new IllegalArgumentException( "Header name cannot contain the following prohibited characters: " + "=,;: \\t\\r\\n\\v\\f "); } } /** * Validates the specified header value * * @param headerValue The value being validated */ static void validateHeaderValue(String headerValue) { //Check to see if the value is null if (headerValue == null) { throw new NullPointerException("Header values cannot be null"); } /* * Set up the state of the validation * * States are as follows: * * 0: Previous character was neither CR nor LF * 1: The previous character was CR * 2: The previous character was LF */ int state = 0; //Start looping through each of the character for (int index = 0; index < headerValue.length(); index ++) { char character = headerValue.charAt(index); //Check the absolutely prohibited characters. switch (character) { case 0x0b: // Vertical tab throw new IllegalArgumentException( "Header value contains a prohibited character '\\v': " + headerValue); case '\f': throw new IllegalArgumentException( "Header value contains a prohibited character '\\f': " + headerValue); } // Check the CRLF (HT | SP) pattern switch (state) { case 0: switch (character) { case '\r': state = 1; break; case '\n': state = 2; break; } break; case 1: switch (character) { case '\n': state = 2; break; default: throw new IllegalArgumentException( "Only '\\n' is allowed after '\\r': " + headerValue); } break; case 2: switch (character) { case '\t': case ' ': state = 0; break; default: throw new IllegalArgumentException( "Only ' ' and '\\t' are allowed after '\\n': " + headerValue); } } } if (state != 0) { throw new IllegalArgumentException( "Header value must not end with '\\r' or '\\n':" + headerValue); } } /** * Checks to see if the transfer encoding in a specified {@link HttpMessage} is chunked * * @param message The message to check * @return True if transfer encoding is chunked, otherwise false */ public static boolean isTransferEncodingChunked(HttpMessage message) { return message.headers().contains(Names.TRANSFER_ENCODING, Values.CHUNKED, true); } public static void removeTransferEncodingChunked(HttpMessage m) { List values = m.headers().getAll(Names.TRANSFER_ENCODING); if (values.isEmpty()) { return; } Iterator valuesIt = values.iterator(); while (valuesIt.hasNext()) { String value = valuesIt.next(); if (value.equalsIgnoreCase(Values.CHUNKED)) { valuesIt.remove(); } } if (values.isEmpty()) { m.headers().remove(Names.TRANSFER_ENCODING); } else { m.headers().set(Names.TRANSFER_ENCODING, values); } } public static void setTransferEncodingChunked(HttpMessage m) { addHeader(m, Names.TRANSFER_ENCODING, Values.CHUNKED); removeHeader(m, Names.CONTENT_LENGTH); } public static boolean isContentLengthSet(HttpMessage m) { return m.headers().contains(Names.CONTENT_LENGTH); } protected HttpHeaders() { } /** * Returns the value of a header with the specified name. If there are * more than one values for the specified name, the first value is returned. * * @param name The name of the header to search * @return The first header value or {@code null} if there is no such header */ public abstract String get(String name); /** * Returns the values of headers with the specified name * * @param name The name of the headers to search * @return A {@link List} of header values which will be empty if no values * are found */ public abstract List getAll(String name); /** * Returns a new {@link List} that contains all headers in this object. Note that modifying the * returned {@link List} will not affect the state of this object. If you intend to enumerate over the header * entries only, use {@link #iterator()} instead, which has much less overhead. */ public abstract List> entries(); /** * Checks to see if there is a header with the specified name * * @param name The name of the header to search for * @return True if at least one header is found */ public abstract boolean contains(String name); /** * Checks if no header exists. */ public abstract boolean isEmpty(); /** * Returns a new {@link Set} that contains the names of all headers in this object. Note that modifying the * returned {@link Set} will not affect the state of this object. If you intend to enumerate over the header * entries only, use {@link #iterator()} instead, which has much less overhead. */ public abstract Set names(); /** * Adds a new header with the specified name and value. * * If the specified value is not a {@link String}, it is converted * into a {@link String} by {@link Object#toString()}, except in the cases * of {@link Date} and {@link Calendar}, which are formatted to the date * format defined in RFC2616. * * @param name The name of the header being added * @param value The value of the header being added * * @return {@code this} */ public abstract HttpHeaders add(String name, Object value); /** * Adds a new header with the specified name and values. * * This getMethod can be represented approximately as the following code: *
     * for (Object v: values) {
     *     if (v == null) {
     *         break;
     *     }
     *     headers.add(name, v);
     * }
     * 
* * @param name The name of the headers being set * @param values The values of the headers being set * @return {@code this} */ public abstract HttpHeaders add(String name, Iterable values); /** * Adds all header entries of the specified {@code headers}. * * @return {@code this} */ public HttpHeaders add(HttpHeaders headers) { if (headers == null) { throw new NullPointerException("headers"); } for (Map.Entry e: headers) { add(e.getKey(), e.getValue()); } return this; } /** * Sets a header with the specified name and value. * * If there is an existing header with the same name, it is removed. * If the specified value is not a {@link String}, it is converted into a * {@link String} by {@link Object#toString()}, except for {@link Date} * and {@link Calendar}, which are formatted to the date format defined in * RFC2616. * * @param name The name of the header being set * @param value The value of the header being set * @return {@code this} */ public abstract HttpHeaders set(String name, Object value); /** * Sets a header with the specified name and values. * * If there is an existing header with the same name, it is removed. * This getMethod can be represented approximately as the following code: *
     * headers.remove(name);
     * for (Object v: values) {
     *     if (v == null) {
     *         break;
     *     }
     *     headers.add(name, v);
     * }
     * 
* * @param name The name of the headers being set * @param values The values of the headers being set * @return {@code this} */ public abstract HttpHeaders set(String name, Iterable values); /** * Cleans the current header entries and copies all header entries of the specified {@code headers}. * * @return {@code this} */ public HttpHeaders set(HttpHeaders headers) { if (headers == null) { throw new NullPointerException("headers"); } clear(); for (Map.Entry e: headers) { add(e.getKey(), e.getValue()); } return this; } /** * Removes the header with the specified name. * * @param name The name of the header to remove * @return {@code this} */ public abstract HttpHeaders remove(String name); /** * Removes all headers from this {@link HttpMessage}. * * @return {@code this} */ public abstract HttpHeaders clear(); /** * Returns {@code true} if a header with the name and value exists. * * @param name the headername * @param value the value * @param ignoreCaseValue {@code true} if case should be ignored * @return contains {@code true} if it contains it {@code false} otherwise */ public boolean contains(String name, String value, boolean ignoreCaseValue) { List values = getAll(name); if (values.isEmpty()) { return false; } for (String v: values) { if (ignoreCaseValue) { if (v.equalsIgnoreCase(value)) { return true; } } else { if (v.equals(value)) { return true; } } } return false; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpMessage.java000066400000000000000000000104421225554127700313400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * An HTTP message which provides common properties for {@link HttpRequest} and * {@link HttpResponse}. * @see HttpHeaders * * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.http.HttpChunk oneway - - is followed by */ public interface HttpMessage { /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated String getHeader(String name); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated List getHeaders(String name); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated List> getHeaders(); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated boolean containsHeader(String name); /** * Returns the {@link Set} of all header names that this message contains. */ @Deprecated Set getHeaderNames(); /** * Returns the protocol version of this message. */ HttpVersion getProtocolVersion(); /** * Sets the protocol version of this message. */ void setProtocolVersion(HttpVersion version); /** * Returns the headers of this message. */ HttpHeaders headers(); /** * Returns the content of this message. If there is no content or * {@link #isChunked()} returns {@code true}, an * {@link ChannelBuffers#EMPTY_BUFFER} is returned. */ ChannelBuffer getContent(); /** * Sets the content of this message. If {@code null} is specified, * the content of this message will be set to {@link ChannelBuffers#EMPTY_BUFFER}. */ void setContent(ChannelBuffer content); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated void addHeader(String name, Object value); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated void setHeader(String name, Object value); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated void setHeader(String name, Iterable values); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated void removeHeader(String name); /** * @deprecated Use {@link HttpMessage#headers()} instead. */ @Deprecated void clearHeaders(); /** * Returns {@code true} if and only if this message does not have any * content but the {@link HttpChunk}s, which is generated by * {@link HttpMessageDecoder} consecutively, contain the actual content. *

* Please note that this method will keep returning {@code true} if the * {@code "Transfer-Encoding"} of this message is {@code "chunked"}, even if * you attempt to override this property by calling {@link #setChunked(boolean)} * with {@code false}. */ boolean isChunked(); /** * Sets if this message does not have any content but the * {@link HttpChunk}s, which is generated by {@link HttpMessageDecoder} * consecutively, contain the actual content. *

* If this method is called with {@code true}, the content of this message * becomes {@link ChannelBuffers#EMPTY_BUFFER}. *

* Even if this method is called with {@code false}, {@link #isChunked()} * will keep returning {@code true} if the {@code "Transfer-Encoding"} of * this message is {@code "chunked"}. */ void setChunked(boolean chunked); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpMessageDecoder.java000066400000000000000000000646231225554127700326400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import java.util.List; /** * Decodes {@link ChannelBuffer}s into {@link HttpMessage}s and * {@link HttpChunk}s. * *

Parameters that prevents excessive memory consumption

* * * * * * * * * * * * * * * * *
NameMeaning
{@code maxInitialLineLength}The maximum length of the initial line * (e.g. {@code "GET / HTTP/1.0"} or {@code "HTTP/1.0 200 OK"}) * If the length of the initial line exceeds this value, a * {@link TooLongFrameException} will be raised.
{@code maxHeaderSize}The maximum length of all headers. If the sum of the length of each * header exceeds this value, a {@link TooLongFrameException} will be raised.
{@code maxChunkSize}The maximum length of the content or each chunk. If the content length * (or the length of each chunk) exceeds this value, the content or chunk * will be split into multiple {@link HttpChunk}s whose length is * {@code maxChunkSize} at maximum.
* *

Chunked Content

* * If the content of an HTTP message is greater than {@code maxChunkSize} or * the transfer encoding of the HTTP message is 'chunked', this decoder * generates one {@link HttpMessage} instance and its following * {@link HttpChunk}s per single HTTP message to avoid excessive memory * consumption. For example, the following HTTP message: *
 * GET / HTTP/1.1
 * Transfer-Encoding: chunked
 *
 * 1a
 * abcdefghijklmnopqrstuvwxyz
 * 10
 * 1234567890abcdef
 * 0
 * Content-MD5: ...
 * [blank line]
 * 
* triggers {@link HttpRequestDecoder} to generate 4 objects: *
    *
  1. An {@link HttpRequest} whose {@link HttpMessage#isChunked() chunked} * property is {@code true},
  2. *
  3. The first {@link HttpChunk} whose content is {@code 'abcdefghijklmnopqrstuvwxyz'},
  4. *
  5. The second {@link HttpChunk} whose content is {@code '1234567890abcdef'}, and
  6. *
  7. An {@link HttpChunkTrailer} which marks the end of the content.
  8. *
* * If you prefer not to handle {@link HttpChunk}s by yourself for your * convenience, insert {@link HttpChunkAggregator} after this decoder in the * {@link ChannelPipeline}. However, please note that your server might not * be as memory efficient as without the aggregator. * *

Extensibility

* * Please note that this decoder is designed to be extended to implement * a protocol derived from HTTP, such as * RTSP and * ICAP. * To implement the decoder of such a derived protocol, extend this class and * implement all abstract methods properly. * @apiviz.landmark */ public abstract class HttpMessageDecoder extends ReplayingDecoder { private final int maxInitialLineLength; private final int maxHeaderSize; private final int maxChunkSize; private HttpMessage message; private ChannelBuffer content; private long chunkSize; private int headerSize; private int contentRead; /** * The internal state of {@link HttpMessageDecoder}. * Internal use only. * @apiviz.exclude */ protected enum State { SKIP_CONTROL_CHARS, READ_INITIAL, READ_HEADER, READ_VARIABLE_LENGTH_CONTENT, READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS, READ_FIXED_LENGTH_CONTENT, READ_FIXED_LENGTH_CONTENT_AS_CHUNKS, READ_CHUNK_SIZE, READ_CHUNKED_CONTENT, READ_CHUNKED_CONTENT_AS_CHUNKS, READ_CHUNK_DELIMITER, READ_CHUNK_FOOTER } /** * Creates a new instance with the default * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxChunkSize (8192)}. */ protected HttpMessageDecoder() { this(4096, 8192, 8192); } /** * Creates a new instance with the specified parameters. */ protected HttpMessageDecoder( int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { super(State.SKIP_CONTROL_CHARS, true); if (maxInitialLineLength <= 0) { throw new IllegalArgumentException( "maxInitialLineLength must be a positive integer: " + maxInitialLineLength); } if (maxHeaderSize <= 0) { throw new IllegalArgumentException( "maxHeaderSize must be a positive integer: " + maxHeaderSize); } if (maxChunkSize < 0) { throw new IllegalArgumentException( "maxChunkSize must be a positive integer: " + maxChunkSize); } this.maxInitialLineLength = maxInitialLineLength; this.maxHeaderSize = maxHeaderSize; this.maxChunkSize = maxChunkSize; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case SKIP_CONTROL_CHARS: { try { skipControlCharacters(buffer); checkpoint(State.READ_INITIAL); } finally { checkpoint(); } } case READ_INITIAL: { String[] initialLine = splitInitialLine(readLine(buffer, maxInitialLineLength)); if (initialLine.length < 3) { // Invalid initial line - ignore. checkpoint(State.SKIP_CONTROL_CHARS); return null; } message = createMessage(initialLine); checkpoint(State.READ_HEADER); } case READ_HEADER: { State nextState = readHeaders(buffer); checkpoint(nextState); if (nextState == State.READ_CHUNK_SIZE) { // Chunked encoding message.setChunked(true); // Generate HttpMessage first. HttpChunks will follow. return message; } if (nextState == State.SKIP_CONTROL_CHARS) { // No content is expected. // Remove the headers which are not supposed to be present not // to confuse subsequent handlers. message.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); return message; } long contentLength = HttpHeaders.getContentLength(message, -1); if (contentLength == 0 || contentLength == -1 && isDecodingRequest()) { content = ChannelBuffers.EMPTY_BUFFER; return reset(); } switch (nextState) { case READ_FIXED_LENGTH_CONTENT: if (contentLength > maxChunkSize || HttpHeaders.is100ContinueExpected(message)) { // Generate HttpMessage first. HttpChunks will follow. checkpoint(State.READ_FIXED_LENGTH_CONTENT_AS_CHUNKS); message.setChunked(true); // chunkSize will be decreased as the READ_FIXED_LENGTH_CONTENT_AS_CHUNKS // state reads data chunk by chunk. chunkSize = HttpHeaders.getContentLength(message, -1); return message; } break; case READ_VARIABLE_LENGTH_CONTENT: if (buffer.readableBytes() > maxChunkSize || HttpHeaders.is100ContinueExpected(message)) { // Generate HttpMessage first. HttpChunks will follow. checkpoint(State.READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS); message.setChunked(true); return message; } break; default: throw new IllegalStateException("Unexpected state: " + nextState); } // We return null here, this forces decode to be called again where we will decode the content return null; } case READ_VARIABLE_LENGTH_CONTENT: { int toRead = actualReadableBytes(); if (toRead > maxChunkSize) { toRead = maxChunkSize; } if (!message.isChunked()) { message.setChunked(true); return new Object[] {message, new DefaultHttpChunk(buffer.readBytes(toRead))}; } else { return new DefaultHttpChunk(buffer.readBytes(toRead)); } } case READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS: { // Keep reading data as a chunk until the end of connection is reached. int toRead = actualReadableBytes(); if (toRead > maxChunkSize) { toRead = maxChunkSize; } HttpChunk chunk = new DefaultHttpChunk(buffer.readBytes(toRead)); if (!buffer.readable()) { // Reached to the end of the connection. reset(); if (!chunk.isLast()) { // Append the last chunk. return new Object[] { chunk, HttpChunk.LAST_CHUNK }; } } return chunk; } case READ_FIXED_LENGTH_CONTENT: { return readFixedLengthContent(buffer); } case READ_FIXED_LENGTH_CONTENT_AS_CHUNKS: { long chunkSize = this.chunkSize; int readLimit = actualReadableBytes(); // Check if the buffer is readable first as we use the readable byte count // to create the HttpChunk. This is needed as otherwise we may end up with // create a HttpChunk instance that contains an empty buffer and so is // handled like it is the last HttpChunk. // // See https://github.com/netty/netty/issues/433 if (readLimit == 0) { return null; } int toRead = readLimit; if (toRead > maxChunkSize) { toRead = maxChunkSize; } if (toRead > chunkSize) { toRead = (int) chunkSize; } HttpChunk chunk = new DefaultHttpChunk(buffer.readBytes(toRead)); if (chunkSize > toRead) { chunkSize -= toRead; } else { chunkSize = 0; } this.chunkSize = chunkSize; if (chunkSize == 0) { // Read all content. reset(); if (!chunk.isLast()) { // Append the last chunk. return new Object[] { chunk, HttpChunk.LAST_CHUNK }; } } return chunk; } /** * everything else after this point takes care of reading chunked content. basically, read chunk size, * read chunk, read and ignore the CRLF and repeat until 0 */ case READ_CHUNK_SIZE: { String line = readLine(buffer, maxInitialLineLength); int chunkSize = getChunkSize(line); this.chunkSize = chunkSize; if (chunkSize == 0) { checkpoint(State.READ_CHUNK_FOOTER); return null; } else if (chunkSize > maxChunkSize) { // A chunk is too large. Split them into multiple chunks again. checkpoint(State.READ_CHUNKED_CONTENT_AS_CHUNKS); } else { checkpoint(State.READ_CHUNKED_CONTENT); } } case READ_CHUNKED_CONTENT: { assert chunkSize <= Integer.MAX_VALUE; HttpChunk chunk = new DefaultHttpChunk(buffer.readBytes((int) chunkSize)); checkpoint(State.READ_CHUNK_DELIMITER); return chunk; } case READ_CHUNKED_CONTENT_AS_CHUNKS: { assert chunkSize <= Integer.MAX_VALUE; int chunkSize = (int) this.chunkSize; int readLimit = actualReadableBytes(); // Check if the buffer is readable first as we use the readable byte count // to create the HttpChunk. This is needed as otherwise we may end up with // create a HttpChunk instance that contains an empty buffer and so is // handled like it is the last HttpChunk. // // See https://github.com/netty/netty/issues/433 if (readLimit == 0) { return null; } int toRead = chunkSize; if (toRead > maxChunkSize) { toRead = maxChunkSize; } if (toRead > readLimit) { toRead = readLimit; } HttpChunk chunk = new DefaultHttpChunk(buffer.readBytes(toRead)); if (chunkSize > toRead) { chunkSize -= toRead; } else { chunkSize = 0; } this.chunkSize = chunkSize; if (chunkSize == 0) { // Read all content. checkpoint(State.READ_CHUNK_DELIMITER); } if (!chunk.isLast()) { return chunk; } } case READ_CHUNK_DELIMITER: { for (;;) { byte next = buffer.readByte(); if (next == HttpConstants.CR) { if (buffer.readByte() == HttpConstants.LF) { checkpoint(State.READ_CHUNK_SIZE); return null; } } else if (next == HttpConstants.LF) { checkpoint(State.READ_CHUNK_SIZE); return null; } } } case READ_CHUNK_FOOTER: { HttpChunkTrailer trailer = readTrailingHeaders(buffer); if (maxChunkSize == 0) { // Chunked encoding disabled. return reset(); } else { reset(); // The last chunk, which is empty return trailer; } } default: { throw new Error("Shouldn't reach here."); } } } protected boolean isContentAlwaysEmpty(HttpMessage msg) { if (msg instanceof HttpResponse) { HttpResponse res = (HttpResponse) msg; int code = res.getStatus().getCode(); // Correctly handle return codes of 1xx. // // See: // - http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html Section 4.4 // - https://github.com/netty/netty/issues/222 if (code >= 100 && code < 200) { if (code == 101 && !res.headers().contains(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT)) { // It's Hixie 76 websocket handshake response return false; } return true; } switch (code) { case 204: case 205: case 304: return true; } } return false; } private Object reset() { HttpMessage message = this.message; ChannelBuffer content = this.content; if (content != null) { message.setContent(content); this.content = null; } this.message = null; checkpoint(State.SKIP_CONTROL_CHARS); return message; } private static void skipControlCharacters(ChannelBuffer buffer) { for (;;) { char c = (char) buffer.readUnsignedByte(); if (!Character.isISOControl(c) && !Character.isWhitespace(c)) { buffer.readerIndex(buffer.readerIndex() - 1); break; } } } private Object readFixedLengthContent(ChannelBuffer buffer) { //we have a content-length so we just read the correct number of bytes long length = HttpHeaders.getContentLength(message, -1); assert length <= Integer.MAX_VALUE; int toRead = (int) length - contentRead; if (toRead > actualReadableBytes()) { toRead = actualReadableBytes(); } contentRead += toRead; if (length < contentRead) { if (!message.isChunked()) { message.setChunked(true); return new Object[] {message, new DefaultHttpChunk(buffer.readBytes(toRead))}; } else { return new DefaultHttpChunk(buffer.readBytes(toRead)); } } if (content == null) { content = buffer.readBytes((int) length); } else { content.writeBytes(buffer, (int) length); } return reset(); } private State readHeaders(ChannelBuffer buffer) throws TooLongFrameException { headerSize = 0; final HttpMessage message = this.message; String line = readHeader(buffer); String name = null; String value = null; if (line.length() != 0) { message.headers().clear(); do { char firstChar = line.charAt(0); if (name != null && (firstChar == ' ' || firstChar == '\t')) { value = value + ' ' + line.trim(); } else { if (name != null) { message.headers().add(name, value); } String[] header = splitHeader(line); name = header[0]; value = header[1]; } line = readHeader(buffer); } while (line.length() != 0); // Add the last header. if (name != null) { message.headers().add(name, value); } } State nextState; if (isContentAlwaysEmpty(message)) { nextState = State.SKIP_CONTROL_CHARS; } else if (message.isChunked()) { // HttpMessage.isChunked() returns true when either: // 1) HttpMessage.setChunked(true) was called or // 2) 'Transfer-Encoding' is 'chunked'. // Because this decoder did not call HttpMessage.setChunked(true) // yet, HttpMessage.isChunked() should return true only when // 'Transfer-Encoding' is 'chunked'. nextState = State.READ_CHUNK_SIZE; } else if (HttpHeaders.getContentLength(message, -1) >= 0) { nextState = State.READ_FIXED_LENGTH_CONTENT; } else { nextState = State.READ_VARIABLE_LENGTH_CONTENT; } return nextState; } private HttpChunkTrailer readTrailingHeaders(ChannelBuffer buffer) throws TooLongFrameException { headerSize = 0; String line = readHeader(buffer); String lastHeader = null; if (line.length() != 0) { HttpChunkTrailer trailer = new DefaultHttpChunkTrailer(); do { char firstChar = line.charAt(0); if (lastHeader != null && (firstChar == ' ' || firstChar == '\t')) { List current = trailer.trailingHeaders().getAll(lastHeader); if (!current.isEmpty()) { int lastPos = current.size() - 1; String newString = current.get(lastPos) + line.trim(); current.set(lastPos, newString); } else { // Content-Length, Transfer-Encoding, or Trailer } } else { String[] header = splitHeader(line); String name = header[0]; if (!name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) && !name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) && !name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) { trailer.trailingHeaders().add(name, header[1]); } lastHeader = name; } line = readHeader(buffer); } while (line.length() != 0); return trailer; } return HttpChunk.LAST_CHUNK; } private String readHeader(ChannelBuffer buffer) throws TooLongFrameException { StringBuilder sb = new StringBuilder(64); int headerSize = this.headerSize; loop: for (;;) { char nextByte = (char) buffer.readByte(); headerSize ++; switch (nextByte) { case HttpConstants.CR: nextByte = (char) buffer.readByte(); headerSize ++; if (nextByte == HttpConstants.LF) { break loop; } break; case HttpConstants.LF: break loop; } // Abort decoding if the header part is too large. if (headerSize >= maxHeaderSize) { // TODO: Respond with Bad Request and discard the traffic // or close the connection. // No need to notify the upstream handlers - just log. // If decoding a response, just throw an exception. throw new TooLongFrameException( "HTTP header is larger than " + maxHeaderSize + " bytes."); } sb.append(nextByte); } this.headerSize = headerSize; return sb.toString(); } protected abstract boolean isDecodingRequest(); protected abstract HttpMessage createMessage(String[] initialLine) throws Exception; private static int getChunkSize(String hex) { hex = hex.trim(); for (int i = 0; i < hex.length(); i ++) { char c = hex.charAt(i); if (c == ';' || Character.isWhitespace(c) || Character.isISOControl(c)) { hex = hex.substring(0, i); break; } } return Integer.parseInt(hex, 16); } private static String readLine(ChannelBuffer buffer, int maxLineLength) throws TooLongFrameException { StringBuilder sb = new StringBuilder(64); int lineLength = 0; while (true) { byte nextByte = buffer.readByte(); if (nextByte == HttpConstants.CR) { nextByte = buffer.readByte(); if (nextByte == HttpConstants.LF) { return sb.toString(); } } else if (nextByte == HttpConstants.LF) { return sb.toString(); } else { if (lineLength >= maxLineLength) { // TODO: Respond with Bad Request and discard the traffic // or close the connection. // No need to notify the upstream handlers - just log. // If decoding a response, just throw an exception. throw new TooLongFrameException( "An HTTP line is larger than " + maxLineLength + " bytes."); } lineLength ++; sb.append((char) nextByte); } } } private static String[] splitInitialLine(String sb) { int aStart; int aEnd; int bStart; int bEnd; int cStart; int cEnd; aStart = findNonWhitespace(sb, 0); aEnd = findWhitespace(sb, aStart); bStart = findNonWhitespace(sb, aEnd); bEnd = findWhitespace(sb, bStart); cStart = findNonWhitespace(sb, bEnd); cEnd = findEndOfString(sb); return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), cStart < cEnd? sb.substring(cStart, cEnd) : "" }; } private static String[] splitHeader(String sb) { final int length = sb.length(); int nameStart; int nameEnd; int colonEnd; int valueStart; int valueEnd; nameStart = findNonWhitespace(sb, 0); for (nameEnd = nameStart; nameEnd < length; nameEnd ++) { char ch = sb.charAt(nameEnd); if (ch == ':' || Character.isWhitespace(ch)) { break; } } for (colonEnd = nameEnd; colonEnd < length; colonEnd ++) { if (sb.charAt(colonEnd) == ':') { colonEnd ++; break; } } valueStart = findNonWhitespace(sb, colonEnd); if (valueStart == length) { return new String[] { sb.substring(nameStart, nameEnd), "" }; } valueEnd = findEndOfString(sb); return new String[] { sb.substring(nameStart, nameEnd), sb.substring(valueStart, valueEnd) }; } private static int findNonWhitespace(String sb, int offset) { int result; for (result = offset; result < sb.length(); result ++) { if (!Character.isWhitespace(sb.charAt(result))) { break; } } return result; } private static int findWhitespace(String sb, int offset) { int result; for (result = offset; result < sb.length(); result ++) { if (Character.isWhitespace(sb.charAt(result))) { break; } } return result; } private static int findEndOfString(String sb) { int result; for (result = sb.length(); result > 0; result --) { if (!Character.isWhitespace(sb.charAt(result - 1))) { break; } } return result; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpMessageEncoder.java000066400000000000000000000155511225554127700326460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpHeaders.Values; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import org.jboss.netty.util.CharsetUtil; import java.io.UnsupportedEncodingException; import java.util.Map; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.jboss.netty.handler.codec.http.HttpConstants.*; /** * Encodes an {@link HttpMessage} or an {@link HttpChunk} into * a {@link ChannelBuffer}. * *

Extensibility

* * Please note that this encoder is designed to be extended to implement * a protocol derived from HTTP, such as * RTSP and * ICAP. * To implement the encoder of such a derived protocol, extend this class and * implement all abstract methods properly. * @apiviz.landmark */ public abstract class HttpMessageEncoder extends OneToOneEncoder { private static final byte[] CRLF = { CR, LF }; private static final ChannelBuffer LAST_CHUNK = copiedBuffer("0\r\n\r\n", CharsetUtil.US_ASCII); private volatile boolean transferEncodingChunked; /** * Creates a new instance. */ protected HttpMessageEncoder() { } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof HttpMessage) { HttpMessage m = (HttpMessage) msg; boolean contentMustBeEmpty; if (m.isChunked()) { // if Content-Length is set then the message can't be HTTP chunked if (HttpCodecUtil.isContentLengthSet(m)) { contentMustBeEmpty = false; transferEncodingChunked = false; HttpCodecUtil.removeTransferEncodingChunked(m); } else { // check if the Transfer-Encoding is set to chunked already. // if not add the header to the message if (!HttpCodecUtil.isTransferEncodingChunked(m)) { m.headers().add(Names.TRANSFER_ENCODING, Values.CHUNKED); } contentMustBeEmpty = true; transferEncodingChunked = true; } } else { transferEncodingChunked = contentMustBeEmpty = HttpCodecUtil.isTransferEncodingChunked(m); } ChannelBuffer header = dynamicBuffer( channel.getConfig().getBufferFactory()); encodeInitialLine(header, m); encodeHeaders(header, m); header.writeByte(CR); header.writeByte(LF); ChannelBuffer content = m.getContent(); if (!content.readable()) { return header; // no content } else if (contentMustBeEmpty) { throw new IllegalArgumentException( "HttpMessage.content must be empty " + "if Transfer-Encoding is chunked."); } else { return wrappedBuffer(header, content); } } if (msg instanceof HttpChunk) { HttpChunk chunk = (HttpChunk) msg; if (transferEncodingChunked) { if (chunk.isLast()) { transferEncodingChunked = false; if (chunk instanceof HttpChunkTrailer) { ChannelBuffer trailer = dynamicBuffer( channel.getConfig().getBufferFactory()); trailer.writeByte((byte) '0'); trailer.writeByte(CR); trailer.writeByte(LF); encodeTrailingHeaders(trailer, (HttpChunkTrailer) chunk); trailer.writeByte(CR); trailer.writeByte(LF); return trailer; } else { return LAST_CHUNK.duplicate(); } } else { ChannelBuffer content = chunk.getContent(); int contentLength = content.readableBytes(); return wrappedBuffer( copiedBuffer( Integer.toHexString(contentLength), CharsetUtil.US_ASCII), wrappedBuffer(CRLF), content.slice(content.readerIndex(), contentLength), wrappedBuffer(CRLF)); } } else { return chunk.getContent(); } } // Unknown message type. return msg; } private static void encodeHeaders(ChannelBuffer buf, HttpMessage message) { try { for (Map.Entry h: message.headers()) { encodeHeader(buf, h.getKey(), h.getValue()); } } catch (UnsupportedEncodingException e) { throw (Error) new Error().initCause(e); } } private static void encodeTrailingHeaders(ChannelBuffer buf, HttpChunkTrailer trailer) { try { for (Map.Entry h: trailer.trailingHeaders()) { encodeHeader(buf, h.getKey(), h.getValue()); } } catch (UnsupportedEncodingException e) { throw (Error) new Error().initCause(e); } } private static void encodeHeader(ChannelBuffer buf, String header, String value) throws UnsupportedEncodingException { encodeAscii(header, buf); buf.writeByte(COLON); buf.writeByte(SP); encodeAscii(value, buf); buf.writeByte(CR); buf.writeByte(LF); } protected static void encodeAscii(String s, ChannelBuffer buf) { for (int i = 0; i < s.length(); i++) { buf.writeByte(s.charAt(i)); } } protected abstract void encodeInitialLine(ChannelBuffer buf, HttpMessage message) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpMethod.java000066400000000000000000000143371225554127700312030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.HashMap; import java.util.Map; /** * The request method of HTTP or its derived protocols, such as * RTSP and * ICAP. * @apiviz.exclude */ public class HttpMethod implements Comparable { /** * The OPTIONS method represents a request for information about the communication options * available on the request/response chain identified by the Request-URI. This method allows * the client to determine the options and/or requirements associated with a resource, or the * capabilities of a server, without implying a resource action or initiating a resource * retrieval. */ public static final HttpMethod OPTIONS = new HttpMethod("OPTIONS"); /** * The GET method means retrieve whatever information (in the form of an entity) is identified * by the Request-URI. If the Request-URI refers to a data-producing process, it is the * produced data which shall be returned as the entity in the response and not the source text * of the process, unless that text happens to be the output of the process. */ public static final HttpMethod GET = new HttpMethod("GET"); /** * The HEAD method is identical to GET except that the server MUST NOT return a message-body in * the response. */ public static final HttpMethod HEAD = new HttpMethod("HEAD"); /** * The POST method is used to request that the origin server accept the entity enclosed in the * request as a new subordinate of the resource identified by the Request-URI in the * Request-Line. */ public static final HttpMethod POST = new HttpMethod("POST"); /** * The PUT method requests that the enclosed entity be stored under the supplied Request-URI. */ public static final HttpMethod PUT = new HttpMethod("PUT"); /** * The PATCH method requests that a set of changes described in the * request entity be applied to the resource identified by the Request-URI. */ public static final HttpMethod PATCH = new HttpMethod("PATCH"); /** * The DELETE method requests that the origin server delete the resource identified by the * Request-URI. */ public static final HttpMethod DELETE = new HttpMethod("DELETE"); /** * The TRACE method is used to invoke a remote, application-layer loop- back of the request * message. */ public static final HttpMethod TRACE = new HttpMethod("TRACE"); /** * This specification reserves the method name CONNECT for use with a proxy that can * dynamically switch to being a tunnel */ public static final HttpMethod CONNECT = new HttpMethod("CONNECT"); private static final Map methodMap = new HashMap(); static { methodMap.put(OPTIONS.toString(), OPTIONS); methodMap.put(GET.toString(), GET); methodMap.put(HEAD.toString(), HEAD); methodMap.put(POST.toString(), POST); methodMap.put(PUT.toString(), PUT); methodMap.put(PATCH.toString(), PATCH); methodMap.put(DELETE.toString(), DELETE); methodMap.put(TRACE.toString(), TRACE); methodMap.put(CONNECT.toString(), CONNECT); } /** * Returns the {@link HttpMethod} represented by the specified name. * If the specified name is a standard HTTP method name, a cached instance * will be returned. Otherwise, a new instance will be returned. */ public static HttpMethod valueOf(String name) { if (name == null) { throw new NullPointerException("name"); } name = name.trim(); if (name.length() == 0) { throw new IllegalArgumentException("empty name"); } HttpMethod result = methodMap.get(name); if (result != null) { return result; } else { return new HttpMethod(name); } } private final String name; /** * Creates a new HTTP method with the specified name. You will not need to * create a new method unless you are implementing a protocol derived from * HTTP, such as * RTSP and * ICAP */ public HttpMethod(String name) { if (name == null) { throw new NullPointerException("name"); } name = name.trim(); if (name.length() == 0) { throw new IllegalArgumentException("empty name"); } for (int i = 0; i < name.length(); i ++) { if (Character.isISOControl(name.charAt(i)) || Character.isWhitespace(name.charAt(i))) { throw new IllegalArgumentException("invalid character in name"); } } this.name = name; } /** * Returns the name of this method. */ public String getName() { return name; } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof HttpMethod)) { return false; } HttpMethod that = (HttpMethod) o; return getName().equals(that.getName()); } @Override public String toString() { return getName(); } public int compareTo(HttpMethod o) { return getName().compareTo(o.getName()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpRequest.java000066400000000000000000000027341225554127700314110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; /** * An HTTP request. * *

Accessing Query Parameters and Cookie

*

* Unlike the Servlet API, a query string is constructed and decomposed by * {@link QueryStringEncoder} and {@link QueryStringDecoder}. {@link Cookie} * support is also provided separately via {@link CookieEncoder} and * {@link CookieDecoder}. * @see HttpResponse * @see CookieEncoder * @see CookieDecoder */ public interface HttpRequest extends HttpMessage { /** * Returns the method of this request. */ HttpMethod getMethod(); /** * Sets the method of this request. */ void setMethod(HttpMethod method); /** * Returns the URI (or path) of this request. */ String getUri(); /** * Sets the URI (or path) of this request. */ void setUri(String uri); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpRequestDecoder.java000066400000000000000000000060131225554127700326710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.frame.TooLongFrameException; /** * Decodes {@link ChannelBuffer}s into {@link HttpRequest}s and {@link HttpChunk}s. * *

Parameters that prevents excessive memory consumption

* * * * * * * * * * * * * * * * *
NameMeaning
{@code maxInitialLineLength}The maximum length of the initial line (e.g. {@code "GET / HTTP/1.0"}) * If the length of the initial line exceeds this value, a * {@link TooLongFrameException} will be raised.
{@code maxHeaderSize}The maximum length of all headers. If the sum of the length of each * header exceeds this value, a {@link TooLongFrameException} will be raised.
{@code maxChunkSize}The maximum length of the content or each chunk. If the content length * exceeds this value, the transfer encoding of the decoded request will be * converted to 'chunked' and the content will be split into multiple * {@link HttpChunk}s. If the transfer encoding of the HTTP request is * 'chunked' already, each chunk will be split into smaller chunks if the * length of the chunk exceeds this value. If you prefer not to handle * {@link HttpChunk}s in your handler, insert {@link HttpChunkAggregator} * after this decoder in the {@link ChannelPipeline}.
*/ public class HttpRequestDecoder extends HttpMessageDecoder { /** * Creates a new instance with the default * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxChunkSize (8192)}. */ public HttpRequestDecoder() { } /** * Creates a new instance with the specified parameters. */ public HttpRequestDecoder( int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { super(maxInitialLineLength, maxHeaderSize, maxChunkSize); } @Override protected HttpMessage createMessage(String[] initialLine) throws Exception { return new DefaultHttpRequest( HttpVersion.valueOf(initialLine[2]), HttpMethod.valueOf(initialLine[0]), initialLine[1]); } @Override protected boolean isDecodingRequest() { return true; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpRequestEncoder.java000066400000000000000000000034761225554127700327150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import static org.jboss.netty.handler.codec.http.HttpConstants.*; /** * Encodes an {@link HttpRequest} or an {@link HttpChunk} into * a {@link ChannelBuffer}. */ public class HttpRequestEncoder extends HttpMessageEncoder { private static final char SLASH = '/'; @Override protected void encodeInitialLine(ChannelBuffer buf, HttpMessage message) throws Exception { HttpRequest request = (HttpRequest) message; buf.writeBytes(request.getMethod().toString().getBytes("ASCII")); buf.writeByte(SP); // Add / as absolute path if no is present. // See http://tools.ietf.org/html/rfc2616#section-5.1.2 String uri = request.getUri(); int start = uri.indexOf("://"); if (start != -1) { int startIndex = start + 3; if (uri.lastIndexOf(SLASH) <= startIndex) { uri += SLASH; } } buf.writeBytes(uri.getBytes("UTF-8")); buf.writeByte(SP); buf.writeBytes(request.getProtocolVersion().toString().getBytes("ASCII")); buf.writeByte(CR); buf.writeByte(LF); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpResponse.java000066400000000000000000000022561225554127700315560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; /** * An HTTP response. * *

Accessing Cookie

*

* Unlike the Servlet API, {@link Cookie} support is provided separately via * {@link CookieEncoder} and {@link CookieDecoder}. * @see HttpRequest * @see CookieEncoder * @see CookieDecoder */ public interface HttpResponse extends HttpMessage { /** * Returns the status of this response. */ HttpResponseStatus getStatus(); /** * Sets the status of this response. */ void setStatus(HttpResponseStatus status); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseDecoder.java000066400000000000000000000106361225554127700330450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.codec.frame.TooLongFrameException; /** * Decodes {@link ChannelBuffer}s into {@link HttpResponse}s and * {@link HttpChunk}s. * *

Parameters that prevents excessive memory consumption

* * * * * * * * * * * * * * * * *
NameMeaning
{@code maxInitialLineLength}The maximum length of the initial line (e.g. {@code "HTTP/1.0 200 OK"}) * If the length of the initial line exceeds this value, a * {@link TooLongFrameException} will be raised.
{@code maxHeaderSize}The maximum length of all headers. If the sum of the length of each * header exceeds this value, a {@link TooLongFrameException} will be raised.
{@code maxChunkSize}The maximum length of the content or each chunk. If the content length * exceeds this value, the transfer encoding of the decoded response will be * converted to 'chunked' and the content will be split into multiple * {@link HttpChunk}s. If the transfer encoding of the HTTP response is * 'chunked' already, each chunk will be split into smaller chunks if the * length of the chunk exceeds this value. If you prefer not to handle * {@link HttpChunk}s in your handler, insert {@link HttpChunkAggregator} * after this decoder in the {@link ChannelPipeline}.
* *

Decoding a response for a HEAD request

*

* Unlike other HTTP requests, the successful response of a HEAD * request does not have any content even if there is Content-Length * header. Because {@link HttpResponseDecoder} is not able to determine if the * response currently being decoded is associated with a HEAD request, * you must override {@link #isContentAlwaysEmpty(HttpMessage)} to return * true for the response of the HEAD request. *

* If you are writing an HTTP client that issues a HEAD request, * please use {@link HttpClientCodec} instead of this decoder. It will perform * additional state management to handle the responses for HEAD * requests correctly. *

* *

Decoding a response for a CONNECT request

*

* You also need to do additional state management to handle the response of a * CONNECT request properly, like you did for HEAD. One * difference is that the decoder should stop decoding completely after decoding * the successful 200 response since the connection is not an HTTP connection * anymore. *

* {@link HttpClientCodec} also handles this edge case correctly, so you have to * use {@link HttpClientCodec} if you are writing an HTTP client that issues a * CONNECT request. *

*/ public class HttpResponseDecoder extends HttpMessageDecoder { /** * Creates a new instance with the default * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxChunkSize (8192)}. */ public HttpResponseDecoder() { } /** * Creates a new instance with the specified parameters. */ public HttpResponseDecoder( int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { super(maxInitialLineLength, maxHeaderSize, maxChunkSize); } @Override protected HttpMessage createMessage(String[] initialLine) { return new DefaultHttpResponse( HttpVersion.valueOf(initialLine[0]), new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2])); } @Override protected boolean isDecodingRequest() { return false; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseEncoder.java000066400000000000000000000026661225554127700330630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.jboss.netty.handler.codec.http.HttpConstants.*; import org.jboss.netty.buffer.ChannelBuffer; /** * Encodes an {@link HttpResponse} or an {@link HttpChunk} into * a {@link ChannelBuffer}. */ public class HttpResponseEncoder extends HttpMessageEncoder { @Override protected void encodeInitialLine(ChannelBuffer buf, HttpMessage message) throws Exception { HttpResponse response = (HttpResponse) message; encodeAscii(response.getProtocolVersion().toString(), buf); buf.writeByte(SP); encodeAscii(String.valueOf(response.getStatus().getCode()), buf); buf.writeByte(SP); encodeAscii(String.valueOf(response.getStatus().getReasonPhrase()), buf); buf.writeByte(CR); buf.writeByte(LF); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseStatus.java000066400000000000000000000347221225554127700327650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; /** * The response code and its description of HTTP or its derived protocols, such as * RTSP and * ICAP. * @apiviz.exclude */ public class HttpResponseStatus implements Comparable { /** * 100 Continue */ public static final HttpResponseStatus CONTINUE = new HttpResponseStatus(100, "Continue"); /** * 101 Switching Protocols */ public static final HttpResponseStatus SWITCHING_PROTOCOLS = new HttpResponseStatus(101, "Switching Protocols"); /** * 102 Processing (WebDAV, RFC2518) */ public static final HttpResponseStatus PROCESSING = new HttpResponseStatus(102, "Processing"); /** * 200 OK */ public static final HttpResponseStatus OK = new HttpResponseStatus(200, "OK"); /** * 201 Created */ public static final HttpResponseStatus CREATED = new HttpResponseStatus(201, "Created"); /** * 202 Accepted */ public static final HttpResponseStatus ACCEPTED = new HttpResponseStatus(202, "Accepted"); /** * 203 Non-Authoritative Information (since HTTP/1.1) */ public static final HttpResponseStatus NON_AUTHORITATIVE_INFORMATION = new HttpResponseStatus(203, "Non-Authoritative Information"); /** * 204 No Content */ public static final HttpResponseStatus NO_CONTENT = new HttpResponseStatus(204, "No Content"); /** * 205 Reset Content */ public static final HttpResponseStatus RESET_CONTENT = new HttpResponseStatus(205, "Reset Content"); /** * 206 Partial Content */ public static final HttpResponseStatus PARTIAL_CONTENT = new HttpResponseStatus(206, "Partial Content"); /** * 207 Multi-Status (WebDAV, RFC2518) */ public static final HttpResponseStatus MULTI_STATUS = new HttpResponseStatus(207, "Multi-Status"); /** * 300 Multiple Choices */ public static final HttpResponseStatus MULTIPLE_CHOICES = new HttpResponseStatus(300, "Multiple Choices"); /** * 301 Moved Permanently */ public static final HttpResponseStatus MOVED_PERMANENTLY = new HttpResponseStatus(301, "Moved Permanently"); /** * 302 Found */ public static final HttpResponseStatus FOUND = new HttpResponseStatus(302, "Found"); /** * 303 See Other (since HTTP/1.1) */ public static final HttpResponseStatus SEE_OTHER = new HttpResponseStatus(303, "See Other"); /** * 304 Not Modified */ public static final HttpResponseStatus NOT_MODIFIED = new HttpResponseStatus(304, "Not Modified"); /** * 305 Use Proxy (since HTTP/1.1) */ public static final HttpResponseStatus USE_PROXY = new HttpResponseStatus(305, "Use Proxy"); /** * 307 Temporary Redirect (since HTTP/1.1) */ public static final HttpResponseStatus TEMPORARY_REDIRECT = new HttpResponseStatus(307, "Temporary Redirect"); /** * 400 Bad Request */ public static final HttpResponseStatus BAD_REQUEST = new HttpResponseStatus(400, "Bad Request"); /** * 401 Unauthorized */ public static final HttpResponseStatus UNAUTHORIZED = new HttpResponseStatus(401, "Unauthorized"); /** * 402 Payment Required */ public static final HttpResponseStatus PAYMENT_REQUIRED = new HttpResponseStatus(402, "Payment Required"); /** * 403 Forbidden */ public static final HttpResponseStatus FORBIDDEN = new HttpResponseStatus(403, "Forbidden"); /** * 404 Not Found */ public static final HttpResponseStatus NOT_FOUND = new HttpResponseStatus(404, "Not Found"); /** * 405 Method Not Allowed */ public static final HttpResponseStatus METHOD_NOT_ALLOWED = new HttpResponseStatus(405, "Method Not Allowed"); /** * 406 Not Acceptable */ public static final HttpResponseStatus NOT_ACCEPTABLE = new HttpResponseStatus(406, "Not Acceptable"); /** * 407 Proxy Authentication Required */ public static final HttpResponseStatus PROXY_AUTHENTICATION_REQUIRED = new HttpResponseStatus(407, "Proxy Authentication Required"); /** * 408 Request Timeout */ public static final HttpResponseStatus REQUEST_TIMEOUT = new HttpResponseStatus(408, "Request Timeout"); /** * 409 Conflict */ public static final HttpResponseStatus CONFLICT = new HttpResponseStatus(409, "Conflict"); /** * 410 Gone */ public static final HttpResponseStatus GONE = new HttpResponseStatus(410, "Gone"); /** * 411 Length Required */ public static final HttpResponseStatus LENGTH_REQUIRED = new HttpResponseStatus(411, "Length Required"); /** * 412 Precondition Failed */ public static final HttpResponseStatus PRECONDITION_FAILED = new HttpResponseStatus(412, "Precondition Failed"); /** * 413 Request Entity Too Large */ public static final HttpResponseStatus REQUEST_ENTITY_TOO_LARGE = new HttpResponseStatus(413, "Request Entity Too Large"); /** * 414 Request-URI Too Long */ public static final HttpResponseStatus REQUEST_URI_TOO_LONG = new HttpResponseStatus(414, "Request-URI Too Long"); /** * 415 Unsupported Media Type */ public static final HttpResponseStatus UNSUPPORTED_MEDIA_TYPE = new HttpResponseStatus(415, "Unsupported Media Type"); /** * 416 Requested Range Not Satisfiable */ public static final HttpResponseStatus REQUESTED_RANGE_NOT_SATISFIABLE = new HttpResponseStatus(416, "Requested Range Not Satisfiable"); /** * 417 Expectation Failed */ public static final HttpResponseStatus EXPECTATION_FAILED = new HttpResponseStatus(417, "Expectation Failed"); /** * 422 Unprocessable Entity (WebDAV, RFC4918) */ public static final HttpResponseStatus UNPROCESSABLE_ENTITY = new HttpResponseStatus(422, "Unprocessable Entity"); /** * 423 Locked (WebDAV, RFC4918) */ public static final HttpResponseStatus LOCKED = new HttpResponseStatus(423, "Locked"); /** * 424 Failed Dependency (WebDAV, RFC4918) */ public static final HttpResponseStatus FAILED_DEPENDENCY = new HttpResponseStatus(424, "Failed Dependency"); /** * 425 Unordered Collection (WebDAV, RFC3648) */ public static final HttpResponseStatus UNORDERED_COLLECTION = new HttpResponseStatus(425, "Unordered Collection"); /** * 426 Upgrade Required (RFC2817) */ public static final HttpResponseStatus UPGRADE_REQUIRED = new HttpResponseStatus(426, "Upgrade Required"); /** * 431 Request Header Fields Too Large (RFC6585) */ public static final HttpResponseStatus REQUEST_HEADER_FIELDS_TOO_LARGE = new HttpResponseStatus(431, "Request Header Fields Too Large"); /** * 500 Internal Server Error */ public static final HttpResponseStatus INTERNAL_SERVER_ERROR = new HttpResponseStatus(500, "Internal Server Error"); /** * 501 Not Implemented */ public static final HttpResponseStatus NOT_IMPLEMENTED = new HttpResponseStatus(501, "Not Implemented"); /** * 502 Bad Gateway */ public static final HttpResponseStatus BAD_GATEWAY = new HttpResponseStatus(502, "Bad Gateway"); /** * 503 Service Unavailable */ public static final HttpResponseStatus SERVICE_UNAVAILABLE = new HttpResponseStatus(503, "Service Unavailable"); /** * 504 Gateway Timeout */ public static final HttpResponseStatus GATEWAY_TIMEOUT = new HttpResponseStatus(504, "Gateway Timeout"); /** * 505 HTTP Version Not Supported */ public static final HttpResponseStatus HTTP_VERSION_NOT_SUPPORTED = new HttpResponseStatus(505, "HTTP Version Not Supported"); /** * 506 Variant Also Negotiates (RFC2295) */ public static final HttpResponseStatus VARIANT_ALSO_NEGOTIATES = new HttpResponseStatus(506, "Variant Also Negotiates"); /** * 507 Insufficient Storage (WebDAV, RFC4918) */ public static final HttpResponseStatus INSUFFICIENT_STORAGE = new HttpResponseStatus(507, "Insufficient Storage"); /** * 510 Not Extended (RFC2774) */ public static final HttpResponseStatus NOT_EXTENDED = new HttpResponseStatus(510, "Not Extended"); /** * Returns the {@link HttpResponseStatus} represented by the specified code. * If the specified code is a standard HTTP status code, a cached instance * will be returned. Otherwise, a new instance will be returned. */ public static HttpResponseStatus valueOf(int code) { switch (code) { case 100: return CONTINUE; case 101: return SWITCHING_PROTOCOLS; case 102: return PROCESSING; case 200: return OK; case 201: return CREATED; case 202: return ACCEPTED; case 203: return NON_AUTHORITATIVE_INFORMATION; case 204: return NO_CONTENT; case 205: return RESET_CONTENT; case 206: return PARTIAL_CONTENT; case 207: return MULTI_STATUS; case 300: return MULTIPLE_CHOICES; case 301: return MOVED_PERMANENTLY; case 302: return FOUND; case 303: return SEE_OTHER; case 304: return NOT_MODIFIED; case 305: return USE_PROXY; case 307: return TEMPORARY_REDIRECT; case 400: return BAD_REQUEST; case 401: return UNAUTHORIZED; case 402: return PAYMENT_REQUIRED; case 403: return FORBIDDEN; case 404: return NOT_FOUND; case 405: return METHOD_NOT_ALLOWED; case 406: return NOT_ACCEPTABLE; case 407: return PROXY_AUTHENTICATION_REQUIRED; case 408: return REQUEST_TIMEOUT; case 409: return CONFLICT; case 410: return GONE; case 411: return LENGTH_REQUIRED; case 412: return PRECONDITION_FAILED; case 413: return REQUEST_ENTITY_TOO_LARGE; case 414: return REQUEST_URI_TOO_LONG; case 415: return UNSUPPORTED_MEDIA_TYPE; case 416: return REQUESTED_RANGE_NOT_SATISFIABLE; case 417: return EXPECTATION_FAILED; case 422: return UNPROCESSABLE_ENTITY; case 423: return LOCKED; case 424: return FAILED_DEPENDENCY; case 425: return UNORDERED_COLLECTION; case 426: return UPGRADE_REQUIRED; case 500: return INTERNAL_SERVER_ERROR; case 501: return NOT_IMPLEMENTED; case 502: return BAD_GATEWAY; case 503: return SERVICE_UNAVAILABLE; case 504: return GATEWAY_TIMEOUT; case 505: return HTTP_VERSION_NOT_SUPPORTED; case 506: return VARIANT_ALSO_NEGOTIATES; case 507: return INSUFFICIENT_STORAGE; case 510: return NOT_EXTENDED; } final String reasonPhrase; if (code < 100) { reasonPhrase = "Unknown Status"; } else if (code < 200) { reasonPhrase = "Informational"; } else if (code < 300) { reasonPhrase = "Successful"; } else if (code < 400) { reasonPhrase = "Redirection"; } else if (code < 500) { reasonPhrase = "Client Error"; } else if (code < 600) { reasonPhrase = "Server Error"; } else { reasonPhrase = "Unknown Status"; } return new HttpResponseStatus(code, reasonPhrase + " (" + code + ')'); } private final int code; private final String reasonPhrase; /** * Creates a new instance with the specified {@code code} and its * {@code reasonPhrase}. */ public HttpResponseStatus(int code, String reasonPhrase) { if (code < 0) { throw new IllegalArgumentException( "code: " + code + " (expected: 0+)"); } if (reasonPhrase == null) { throw new NullPointerException("reasonPhrase"); } for (int i = 0; i < reasonPhrase.length(); i ++) { char c = reasonPhrase.charAt(i); // Check prohibited characters. switch (c) { case '\n': case '\r': throw new IllegalArgumentException( "reasonPhrase contains one of the following prohibited characters: " + "\\r\\n: " + reasonPhrase); } } this.code = code; this.reasonPhrase = reasonPhrase; } /** * Returns the code of this status. */ public int getCode() { return code; } /** * Returns the reason phrase of this status. */ public String getReasonPhrase() { return reasonPhrase; } @Override public int hashCode() { return getCode(); } @Override public boolean equals(Object o) { if (!(o instanceof HttpResponseStatus)) { return false; } return getCode() == ((HttpResponseStatus) o).getCode(); } public int compareTo(HttpResponseStatus o) { return getCode() - o.getCode(); } @Override public String toString() { StringBuilder buf = new StringBuilder(reasonPhrase.length() + 5); buf.append(code); buf.append(' '); buf.append(reasonPhrase); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpServerCodec.java000066400000000000000000000043551225554127700321660ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelUpstreamHandler; /** * A combination of {@link HttpRequestDecoder} and {@link HttpResponseEncoder} * which enables easier server side HTTP implementation. * @see HttpClientCodec * * @apiviz.has org.jboss.netty.handler.codec.http.HttpRequestDecoder * @apiviz.has org.jboss.netty.handler.codec.http.HttpResponseEncoder */ public class HttpServerCodec implements ChannelUpstreamHandler, ChannelDownstreamHandler { private final HttpRequestDecoder decoder; private final HttpResponseEncoder encoder = new HttpResponseEncoder(); /** * Creates a new instance with the default decoder options * ({@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxChunkSize (8192)}). */ public HttpServerCodec() { this(4096, 8192, 8192); } /** * Creates a new instance with the specified decoder options. */ public HttpServerCodec( int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { decoder = new HttpRequestDecoder(maxInitialLineLength, maxHeaderSize, maxChunkSize); } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { decoder.handleUpstream(ctx, e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { encoder.handleDownstream(ctx, e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/HttpVersion.java000066400000000000000000000174471225554127700314150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * The version of HTTP or its derived protocols, such as * RTSP and * ICAP. * @apiviz.exclude */ public class HttpVersion implements Comparable { private static final Pattern VERSION_PATTERN = Pattern.compile("(\\S+)/(\\d+)\\.(\\d+)"); /** * HTTP/1.0 */ public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false); /** * HTTP/1.1 */ public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true); /** * Returns an existing or new {@link HttpVersion} instance which matches to * the specified protocol version string. If the specified {@code text} is * equal to {@code "HTTP/1.0"}, {@link #HTTP_1_0} will be returned. If the * specified {@code text} is equal to {@code "HTTP/1.1"}, {@link #HTTP_1_1} * will be returned. Otherwise, a new {@link HttpVersion} instance will be * returned. */ public static HttpVersion valueOf(String text) { if (text == null) { throw new NullPointerException("text"); } text = text.trim().toUpperCase(); if ("HTTP/1.1".equals(text)) { return HTTP_1_1; } if ("HTTP/1.0".equals(text)) { return HTTP_1_0; } return new HttpVersion(text, true); } private final String protocolName; private final int majorVersion; private final int minorVersion; private final String text; private final boolean keepAliveDefault; /** * @deprecated Use {@link #HttpVersion(String, boolean)} instead. */ @Deprecated public HttpVersion(String text) { this(text, true); } /** * Creates a new HTTP version with the specified version string. You will * not need to create a new instance unless you are implementing a protocol * derived from HTTP, such as * RTSP and * ICAP. * * @param keepAliveDefault * {@code true} if and only if the connection is kept alive unless * the {@code "Connection"} header is set to {@code "close"} explicitly. */ public HttpVersion(String text, boolean keepAliveDefault) { if (text == null) { throw new NullPointerException("text"); } text = text.trim().toUpperCase(); if (text.length() == 0) { throw new IllegalArgumentException("empty text"); } Matcher m = VERSION_PATTERN.matcher(text); if (!m.matches()) { throw new IllegalArgumentException("invalid version format: " + text); } protocolName = m.group(1); majorVersion = Integer.parseInt(m.group(2)); minorVersion = Integer.parseInt(m.group(3)); this.text = protocolName + '/' + majorVersion + '.' + minorVersion; this.keepAliveDefault = keepAliveDefault; } /** * @deprecated Use {@link #HttpVersion(String, int, int, boolean)} instead. */ @Deprecated public HttpVersion( String protocolName, int majorVersion, int minorVersion) { this(protocolName, majorVersion, minorVersion, true); } /** * Creates a new HTTP version with the specified protocol name and version * numbers. You will not need to create a new instance unless you are * implementing a protocol derived from HTTP, such as * RTSP and * ICAP * * @param keepAliveDefault * {@code true} if and only if the connection is kept alive unless * the {@code "Connection"} header is set to {@code "close"} explicitly. */ public HttpVersion( String protocolName, int majorVersion, int minorVersion, boolean keepAliveDefault) { if (protocolName == null) { throw new NullPointerException("protocolName"); } protocolName = protocolName.trim().toUpperCase(); if (protocolName.length() == 0) { throw new IllegalArgumentException("empty protocolName"); } for (int i = 0; i < protocolName.length(); i ++) { if (Character.isISOControl(protocolName.charAt(i)) || Character.isWhitespace(protocolName.charAt(i))) { throw new IllegalArgumentException("invalid character in protocolName"); } } if (majorVersion < 0) { throw new IllegalArgumentException("negative majorVersion"); } if (minorVersion < 0) { throw new IllegalArgumentException("negative minorVersion"); } this.protocolName = protocolName; this.majorVersion = majorVersion; this.minorVersion = minorVersion; text = protocolName + '/' + majorVersion + '.' + minorVersion; this.keepAliveDefault = keepAliveDefault; } /** * Returns the name of the protocol such as {@code "HTTP"} in {@code "HTTP/1.0"}. */ public String getProtocolName() { return protocolName; } /** * Returns the name of the protocol such as {@code 1} in {@code "HTTP/1.0"}. */ public int getMajorVersion() { return majorVersion; } /** * Returns the name of the protocol such as {@code 0} in {@code "HTTP/1.0"}. */ public int getMinorVersion() { return minorVersion; } /** * Returns the full protocol version text such as {@code "HTTP/1.0"}. */ public String getText() { return text; } /** * Returns {@code true} if and only if the connection is kept alive unless * the {@code "Connection"} header is set to {@code "close"} explicitly. */ public boolean isKeepAliveDefault() { return keepAliveDefault; } /** * Returns the full protocol version text such as {@code "HTTP/1.0"}. */ @Override public String toString() { return getText(); } @Override public int hashCode() { return (getProtocolName().hashCode() * 31 + getMajorVersion()) * 31 + getMinorVersion(); } @Override public boolean equals(Object o) { if (!(o instanceof HttpVersion)) { return false; } HttpVersion that = (HttpVersion) o; return getMinorVersion() == that.getMinorVersion() && getMajorVersion() == that.getMajorVersion() && getProtocolName().equals(that.getProtocolName()); } public int compareTo(HttpVersion o) { int v = getProtocolName().compareTo(o.getProtocolName()); if (v != 0) { return v; } v = getMajorVersion() - o.getMajorVersion(); if (v != 0) { return v; } return getMinorVersion() - o.getMinorVersion(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/QueryStringDecoder.java000066400000000000000000000346761225554127700327150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.util.CharsetUtil; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Splits an HTTP query string into a path string and key-value parameter pairs. * This decoder is for one time use only. Create a new instance for each URI: *
 * {@link QueryStringDecoder} decoder = new {@link QueryStringDecoder}("/hello?recipient=world&x=1;y=2");
 * assert decoder.getPath().equals("/hello");
 * assert decoder.getParameters().get("recipient").get(0).equals("world");
 * assert decoder.getParameters().get("x").get(0).equals("1");
 * assert decoder.getParameters().get("y").get(0).equals("2");
 * 
* * This decoder can also decode the content of an HTTP POST request whose * content type is application/x-www-form-urlencoded: *
 * {@link QueryStringDecoder} decoder = new {@link QueryStringDecoder}("recipient=world&x=1;y=2", false);
 * ...
 * 
* *

HashDOS vulnerability fix

* * As a workaround to the HashDOS vulnerability, the decoder * limits the maximum number of decoded key-value parameter pairs, up to {@literal 1024} by * default, and you can configure it when you construct the decoder by passing an additional * integer parameter. * * @see QueryStringEncoder * * @apiviz.stereotype utility * @apiviz.has org.jboss.netty.handler.codec.http.HttpRequest oneway - - decodes */ public class QueryStringDecoder { private static final int DEFAULT_MAX_PARAMS = 1024; private final Charset charset; private final String uri; private final boolean hasPath; private final int maxParams; private String path; private Map> params; private int nParams; /** * Creates a new decoder that decodes the specified URI. The decoder will * assume that the query string is encoded in UTF-8. */ public QueryStringDecoder(String uri) { this(uri, HttpConstants.DEFAULT_CHARSET); } /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(String uri, boolean hasPath) { this(uri, HttpConstants.DEFAULT_CHARSET, hasPath); } /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(String uri, Charset charset) { this(uri, charset, true); } /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(String uri, Charset charset, boolean hasPath) { this(uri, charset, hasPath, DEFAULT_MAX_PARAMS); } /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(String uri, Charset charset, boolean hasPath, int maxParams) { if (uri == null) { throw new NullPointerException("uri"); } if (charset == null) { throw new NullPointerException("charset"); } if (maxParams <= 0) { throw new IllegalArgumentException( "maxParams: " + maxParams + " (expected: a positive integer)"); } this.uri = uri; this.charset = charset; this.maxParams = maxParams; this.hasPath = hasPath; } /** * @deprecated Use {@link #QueryStringDecoder(String, Charset)} instead. */ @Deprecated public QueryStringDecoder(String uri, String charset) { this(uri, Charset.forName(charset)); } /** * Creates a new decoder that decodes the specified URI. The decoder will * assume that the query string is encoded in UTF-8. */ public QueryStringDecoder(URI uri) { this(uri, HttpConstants.DEFAULT_CHARSET); } /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(URI uri, Charset charset) { this(uri, charset, DEFAULT_MAX_PARAMS); } /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(URI uri, Charset charset, int maxParams) { if (uri == null) { throw new NullPointerException("uri"); } if (charset == null) { throw new NullPointerException("charset"); } if (maxParams <= 0) { throw new IllegalArgumentException( "maxParams: " + maxParams + " (expected: a positive integer)"); } String rawPath = uri.getRawPath(); if (rawPath != null) { hasPath = true; } else { rawPath = ""; hasPath = false; } // Also take care of cut of things like "http://localhost" this.uri = rawPath + '?' + uri.getRawQuery(); this.charset = charset; this.maxParams = maxParams; } /** * @deprecated Use {@link #QueryStringDecoder(URI, Charset)} instead. */ @Deprecated public QueryStringDecoder(URI uri, String charset) { this(uri, Charset.forName(charset)); } /** * Returns the decoded path string of the URI. */ public String getPath() { if (path == null) { if (!hasPath) { return path = ""; } int pathEndPos = uri.indexOf('?'); if (pathEndPos < 0) { path = uri; } else { return path = uri.substring(0, pathEndPos); } } return path; } /** * Returns the decoded key-value parameter pairs of the URI. */ public Map> getParameters() { if (params == null) { if (hasPath) { int pathLength = getPath().length(); if (uri.length() == pathLength) { return Collections.emptyMap(); } decodeParams(uri.substring(pathLength + 1)); } else { if (uri.length() == 0) { return Collections.emptyMap(); } decodeParams(uri); } } return params; } private void decodeParams(String s) { Map> params = this.params = new LinkedHashMap>(); nParams = 0; String name = null; int pos = 0; // Beginning of the unprocessed region int i; // End of the unprocessed region char c; // Current character for (i = 0; i < s.length(); i++) { c = s.charAt(i); if (c == '=' && name == null) { if (pos != i) { name = decodeComponent(s.substring(pos, i), charset); } pos = i + 1; // http://www.w3.org/TR/html401/appendix/notes.html#h-B.2.2 } else if (c == '&' || c == ';') { if (name == null && pos != i) { // We haven't seen an `=' so far but moved forward. // Must be a param of the form '&a&' so add it with // an empty value. if (!addParam(params, decodeComponent(s.substring(pos, i), charset), "")) { return; } } else if (name != null) { if (!addParam(params, name, decodeComponent(s.substring(pos, i), charset))) { return; } name = null; } pos = i + 1; } } if (pos != i) { // Are there characters we haven't dealt with? if (name == null) { // Yes and we haven't seen any `='. addParam(params, decodeComponent(s.substring(pos, i), charset), ""); } else { // Yes and this must be the last value. addParam(params, name, decodeComponent(s.substring(pos, i), charset)); } } else if (name != null) { // Have we seen a name without value? addParam(params, name, ""); } } private boolean addParam(Map> params, String name, String value) { if (nParams >= maxParams) { return false; } List values = params.get(name); if (values == null) { values = new ArrayList(1); // Often there's only 1 value. params.put(name, values); } values.add(value); nParams ++; return true; } /** * Decodes a bit of an URL encoded by a browser. *

* This is equivalent to calling {@link #decodeComponent(String, Charset)} * with the UTF-8 charset (recommended to comply with RFC 3986, Section 2). * @param s The string to decode (can be empty). * @return The decoded string, or {@code s} if there's nothing to decode. * If the string to decode is {@code null}, returns an empty string. * @throws IllegalArgumentException if the string contains a malformed * escape sequence. */ public static String decodeComponent(final String s) { return decodeComponent(s, HttpConstants.DEFAULT_CHARSET); } /** * Decodes a bit of an URL encoded by a browser. *

* The string is expected to be encoded as per RFC 3986, Section 2. * This is the encoding used by JavaScript functions {@code encodeURI} * and {@code encodeURIComponent}, but not {@code escape}. For example * in this encoding, é (in Unicode {@code U+00E9} or in UTF-8 * {@code 0xC3 0xA9}) is encoded as {@code %C3%A9} or {@code %c3%a9}. *

* This is essentially equivalent to calling * {@link URLDecoder#decode(String, String) URLDecoder.decode(s, charset.name())} * except that it's over 2x faster and generates less garbage for the GC. * Actually this function doesn't allocate any memory if there's nothing * to decode, the argument itself is returned. * @param s The string to decode (can be empty). * @param charset The charset to use to decode the string (should really * be {@link CharsetUtil#UTF_8}. * @return The decoded string, or {@code s} if there's nothing to decode. * If the string to decode is {@code null}, returns an empty string. * @throws IllegalArgumentException if the string contains a malformed * escape sequence. */ @SuppressWarnings("fallthrough") public static String decodeComponent(final String s, final Charset charset) { if (s == null) { return ""; } final int size = s.length(); boolean modified = false; for (int i = 0; i < size; i++) { final char c = s.charAt(i); switch (c) { case '%': i++; // We can skip at least one char, e.g. `%%'. // Fall through. case '+': modified = true; break; } } if (!modified) { return s; } final byte[] buf = new byte[size]; int pos = 0; // position in `buf'. for (int i = 0; i < size; i++) { char c = s.charAt(i); switch (c) { case '+': buf[pos++] = ' '; // "+" -> " " break; case '%': if (i == size - 1) { throw new IllegalArgumentException("unterminated escape" + " sequence at end of string: " + s); } c = s.charAt(++i); if (c == '%') { buf[pos++] = '%'; // "%%" -> "%" break; } if (i == size - 1) { throw new IllegalArgumentException("partial escape" + " sequence at end of string: " + s); } c = decodeHexNibble(c); final char c2 = decodeHexNibble(s.charAt(++i)); if (c == Character.MAX_VALUE || c2 == Character.MAX_VALUE) { throw new IllegalArgumentException( "invalid escape sequence `%" + s.charAt(i - 1) + s.charAt(i) + "' at index " + (i - 2) + " of: " + s); } c = (char) (c * 16 + c2); // Fall through. default: buf[pos++] = (byte) c; break; } } try { return new String(buf, 0, pos, charset.name()); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException("unsupported encoding: " + charset.name(), e); } } /** * Helper to decode half of a hexadecimal number from a string. * @param c The ASCII character of the hexadecimal number to decode. * Must be in the range {@code [0-9a-fA-F]}. * @return The hexadecimal value represented in the ASCII character * given, or {@link Character#MAX_VALUE} if the character is invalid. */ private static char decodeHexNibble(final char c) { if ('0' <= c && c <= '9') { return (char) (c - '0'); } else if ('a' <= c && c <= 'f') { return (char) (c - 'a' + 10); } else if ('A' <= c && c <= 'F') { return (char) (c - 'A' + 10); } else { return Character.MAX_VALUE; } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/QueryStringEncoder.java000066400000000000000000000107501225554127700327120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.List; /** * Creates an URL-encoded URI from a path string and key-value parameter pairs. * This encoder is for one time use only. Create a new instance for each URI. * *

 * {@link QueryStringEncoder} encoder = new {@link QueryStringEncoder}("/hello");
 * encoder.addParam("recipient", "world");
 * assert encoder.toString().equals("/hello?recipient=world");
 * 
* @see QueryStringDecoder * * @apiviz.stereotype utility * @apiviz.has org.jboss.netty.handler.codec.http.HttpRequest oneway - - encodes */ public class QueryStringEncoder { private final Charset charset; private final String uri; private final List params = new ArrayList(); /** * Creates a new encoder that encodes a URI that starts with the specified * path string. The encoder will encode the URI in UTF-8. */ public QueryStringEncoder(String uri) { this(uri, HttpConstants.DEFAULT_CHARSET); } /** * Creates a new encoder that encodes a URI that starts with the specified * path string in the specified charset. */ public QueryStringEncoder(String uri, Charset charset) { if (uri == null) { throw new NullPointerException("uri"); } if (charset == null) { throw new NullPointerException("charset"); } this.uri = uri; this.charset = charset; } /** * @deprecated Use {@link #QueryStringEncoder(String, Charset)} instead. */ @Deprecated public QueryStringEncoder(String uri, String charset) { this(uri, Charset.forName(charset)); } /** * Adds a parameter with the specified name and value to this encoder. */ public void addParam(String name, String value) { if (name == null) { throw new NullPointerException("name"); } if (value == null) { throw new NullPointerException("value"); } params.add(new Param(name, value)); } /** * Returns the URL-encoded URI object which was created from the path string * specified in the constructor and the parameters added by * {@link #addParam(String, String)} method. */ public URI toUri() throws URISyntaxException { return new URI(toString()); } /** * Returns the URL-encoded URI which was created from the path string * specified in the constructor and the parameters added by * {@link #addParam(String, String)} method. */ @Override public String toString() { if (params.isEmpty()) { return uri; } else { StringBuilder sb = new StringBuilder(uri).append('?'); for (int i = 0; i < params.size(); i++) { Param param = params.get(i); sb.append(encodeComponent(param.name, charset)); sb.append('='); sb.append(encodeComponent(param.value, charset)); if (i != params.size() - 1) { sb.append('&'); } } return sb.toString(); } } private static String encodeComponent(String s, Charset charset) { try { return URLEncoder.encode(s, charset.name()).replaceAll("\\+", "%20"); } catch (UnsupportedEncodingException e) { throw new UnsupportedCharsetException(charset.name()); } } private static final class Param { final String name; final String value; Param(String name, String value) { this.value = value; this.name = name; } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/000077500000000000000000000000001225554127700302715ustar00rootroot00000000000000AbstractDiskHttpData.java000066400000000000000000000252661225554127700351000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.HttpConstants; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; /** * Abstract Disk HttpData implementation */ public abstract class AbstractDiskHttpData extends AbstractHttpData { protected File file; private boolean isRenamed; private FileChannel fileChannel; protected AbstractDiskHttpData(String name, Charset charset, long size) { super(name, charset, size); } /** * * @return the real DiskFilename (basename) */ protected abstract String getDiskFilename(); /** * * @return the default prefix */ protected abstract String getPrefix(); /** * * @return the default base Directory */ protected abstract String getBaseDirectory(); /** * * @return the default postfix */ protected abstract String getPostfix(); /** * * @return True if the file should be deleted on Exit by default */ protected abstract boolean deleteOnExit(); /** * @return a new Temp File from getDiskFilename(), default prefix, postfix and baseDirectory */ private File tempFile() throws IOException { String newpostfix; String diskFilename = getDiskFilename(); if (diskFilename != null) { newpostfix = '_' + diskFilename; } else { newpostfix = getPostfix(); } File tmpFile; if (getBaseDirectory() == null) { // create a temporary file tmpFile = File.createTempFile(getPrefix(), newpostfix); } else { tmpFile = File.createTempFile(getPrefix(), newpostfix, new File( getBaseDirectory())); } if (deleteOnExit()) { tmpFile.deleteOnExit(); } return tmpFile; } public void setContent(ChannelBuffer buffer) throws IOException { if (buffer == null) { throw new NullPointerException("buffer"); } size = buffer.readableBytes(); checkSize(size); if (definedSize > 0 && definedSize < size) { throw new IOException("Out of size: " + size + " > " + definedSize); } if (file == null) { file = tempFile(); } if (buffer.readableBytes() == 0) { // empty file file.createNewFile(); return; } FileOutputStream outputStream = new FileOutputStream(file); FileChannel localfileChannel = outputStream.getChannel(); ByteBuffer byteBuffer = buffer.toByteBuffer(); int written = 0; while (written < size) { written += localfileChannel.write(byteBuffer); } buffer.readerIndex(buffer.readerIndex() + written); localfileChannel.force(false); localfileChannel.close(); outputStream.close(); completed = true; } public void addContent(ChannelBuffer buffer, boolean last) throws IOException { if (buffer != null) { int localsize = buffer.readableBytes(); checkSize(size + localsize); if (definedSize > 0 && definedSize < size + localsize) { throw new IOException("Out of size: " + (size + localsize) + " > " + definedSize); } ByteBuffer byteBuffer = buffer.toByteBuffer(); int written = 0; if (file == null) { file = tempFile(); } if (fileChannel == null) { FileOutputStream outputStream = new FileOutputStream(file); fileChannel = outputStream.getChannel(); } while (written < localsize) { written += fileChannel.write(byteBuffer); } size += localsize; buffer.readerIndex(buffer.readerIndex() + written); } if (last) { if (file == null) { file = tempFile(); } if (fileChannel == null) { FileOutputStream outputStream = new FileOutputStream(file); fileChannel = outputStream.getChannel(); } fileChannel.force(false); fileChannel.close(); fileChannel = null; completed = true; } else { if (buffer == null) { throw new NullPointerException("buffer"); } } } public void setContent(File file) throws IOException { if (this.file != null) { delete(); } this.file = file; size = file.length(); checkSize(size); isRenamed = true; completed = true; } public void setContent(InputStream inputStream) throws IOException { if (inputStream == null) { throw new NullPointerException("inputStream"); } if (file != null) { delete(); } file = tempFile(); FileOutputStream outputStream = new FileOutputStream(file); FileChannel localfileChannel = outputStream.getChannel(); byte[] bytes = new byte[4096 * 4]; ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); int read = inputStream.read(bytes); int written = 0; while (read > 0) { byteBuffer.position(read).flip(); written += localfileChannel.write(byteBuffer); checkSize(written); read = inputStream.read(bytes); } localfileChannel.force(false); localfileChannel.close(); size = written; if (definedSize > 0 && definedSize < size) { file.delete(); file = null; throw new IOException("Out of size: " + size + " > " + definedSize); } isRenamed = true; completed = true; } public void delete() { if (! isRenamed) { if (file != null) { file.delete(); } } } public byte[] get() throws IOException { if (file == null) { return new byte[0]; } return readFrom(file); } public ChannelBuffer getChannelBuffer() throws IOException { if (file == null) { return ChannelBuffers.EMPTY_BUFFER; } byte[] array = readFrom(file); return ChannelBuffers.wrappedBuffer(array); } public ChannelBuffer getChunk(int length) throws IOException { if (file == null || length == 0) { return ChannelBuffers.EMPTY_BUFFER; } if (fileChannel == null) { FileInputStream inputStream = new FileInputStream(file); fileChannel = inputStream.getChannel(); } int read = 0; ByteBuffer byteBuffer = ByteBuffer.allocate(length); while (read < length) { int readnow = fileChannel.read(byteBuffer); if (readnow == -1) { fileChannel.close(); fileChannel = null; break; } else { read += readnow; } } if (read == 0) { return ChannelBuffers.EMPTY_BUFFER; } byteBuffer.flip(); ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(byteBuffer); buffer.readerIndex(0); buffer.writerIndex(read); return buffer; } public String getString() throws IOException { return getString(HttpConstants.DEFAULT_CHARSET); } public String getString(Charset encoding) throws IOException { if (file == null) { return ""; } if (encoding == null) { byte[] array = readFrom(file); return new String(array, HttpConstants.DEFAULT_CHARSET.name()); } byte[] array = readFrom(file); return new String(array, encoding.name()); } public boolean isInMemory() { return false; } public boolean renameTo(File dest) throws IOException { if (dest == null) { throw new NullPointerException("dest"); } if (!file.renameTo(dest)) { // must copy FileInputStream inputStream = new FileInputStream(file); FileOutputStream outputStream = new FileOutputStream(dest); FileChannel in = inputStream.getChannel(); FileChannel out = outputStream.getChannel(); int chunkSize = 8196; long position = 0; while (position < size) { if (chunkSize < size - position) { chunkSize = (int) (size - position); } position += in.transferTo(position, chunkSize , out); } in.close(); out.close(); if (position == size) { file.delete(); file = dest; isRenamed = true; return true; } else { dest.delete(); return false; } } file = dest; isRenamed = true; return true; } /** * Utility function * @return the array of bytes */ private static byte[] readFrom(File src) throws IOException { long srcsize = src.length(); if (srcsize > Integer.MAX_VALUE) { throw new IllegalArgumentException( "File too big to be loaded in memory"); } FileInputStream inputStream = new FileInputStream(src); FileChannel fileChannel = inputStream.getChannel(); byte[] array = new byte[(int) srcsize]; ByteBuffer byteBuffer = ByteBuffer.wrap(array); int read = 0; while (read < srcsize) { read += fileChannel.read(byteBuffer); } fileChannel.close(); return array; } public File getFile() throws IOException { return file; } } AbstractHttpData.java000066400000000000000000000050571225554127700342610ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.handler.codec.http.HttpConstants; import java.io.IOException; import java.nio.charset.Charset; import java.util.regex.Pattern; /** * Abstract HttpData implementation */ public abstract class AbstractHttpData implements HttpData { private static final Pattern STRIP_PATTERN = Pattern.compile("(?:^\\s+|\\s+$|\\n)"); private static final Pattern REPLACE_PATTERN = Pattern.compile("[\\r\\t]"); protected final String name; protected long definedSize; protected long size; protected Charset charset = HttpConstants.DEFAULT_CHARSET; protected boolean completed; protected long maxSize = DefaultHttpDataFactory.MAXSIZE; protected AbstractHttpData(String name, Charset charset, long size) { if (name == null) { throw new NullPointerException("name"); } name = REPLACE_PATTERN.matcher(name).replaceAll(" "); name = STRIP_PATTERN.matcher(name).replaceAll(""); if (name.length() == 0) { throw new IllegalArgumentException("empty name"); } this.name = name; if (charset != null) { setCharset(charset); } definedSize = size; } public void setMaxSize(long maxSize) { this.maxSize = maxSize; } public void checkSize(long newSize) throws IOException { if (maxSize >= 0 && newSize > maxSize) { throw new IOException("Size exceed allowed maximum capacity"); } } public String getName() { return name; } public boolean isCompleted() { return completed; } public Charset getCharset() { return charset; } public void setCharset(Charset charset) { if (charset == null) { throw new NullPointerException("charset"); } this.charset = charset; } public long length() { return size; } } AbstractMemoryHttpData.java000066400000000000000000000160411225554127700354450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.HttpConstants; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; /** * Abstract Memory HttpData implementation */ public abstract class AbstractMemoryHttpData extends AbstractHttpData { private ChannelBuffer channelBuffer; private int chunkPosition; protected boolean isRenamed; protected AbstractMemoryHttpData(String name, Charset charset, long size) { super(name, charset, size); } public void setContent(ChannelBuffer buffer) throws IOException { if (buffer == null) { throw new NullPointerException("buffer"); } long localsize = buffer.readableBytes(); checkSize(localsize); if (definedSize > 0 && definedSize < localsize) { throw new IOException("Out of size: " + localsize + " > " + definedSize); } channelBuffer = buffer; size = localsize; completed = true; } public void setContent(InputStream inputStream) throws IOException { if (inputStream == null) { throw new NullPointerException("inputStream"); } ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(); byte[] bytes = new byte[4096 * 4]; int read = inputStream.read(bytes); int written = 0; while (read > 0) { buffer.writeBytes(bytes, 0, read); written += read; checkSize(written); read = inputStream.read(bytes); } size = written; if (definedSize > 0 && definedSize < size) { throw new IOException("Out of size: " + size + " > " + definedSize); } channelBuffer = buffer; completed = true; } public void addContent(ChannelBuffer buffer, boolean last) throws IOException { if (buffer != null) { long localsize = buffer.readableBytes(); checkSize(size + localsize); if (definedSize > 0 && definedSize < size + localsize) { throw new IOException("Out of size: " + (size + localsize) + " > " + definedSize); } size += localsize; if (channelBuffer == null) { channelBuffer = buffer; } else { channelBuffer = ChannelBuffers.wrappedBuffer( channelBuffer, buffer); } } if (last) { completed = true; } else { if (buffer == null) { throw new NullPointerException("buffer"); } } } public void setContent(File file) throws IOException { if (file == null) { throw new NullPointerException("file"); } long newsize = file.length(); if (newsize > Integer.MAX_VALUE) { throw new IllegalArgumentException( "File too big to be loaded in memory"); } checkSize(newsize); FileInputStream inputStream = new FileInputStream(file); FileChannel fileChannel = inputStream.getChannel(); byte[] array = new byte[(int) newsize]; ByteBuffer byteBuffer = ByteBuffer.wrap(array); int read = 0; while (read < newsize) { read += fileChannel.read(byteBuffer); } fileChannel.close(); inputStream.close(); byteBuffer.flip(); channelBuffer = ChannelBuffers.wrappedBuffer(byteBuffer); size = newsize; completed = true; } public void delete() { // nothing to do } public byte[] get() { if (channelBuffer == null) { return new byte[0]; } byte[] array = new byte[channelBuffer.readableBytes()]; channelBuffer.getBytes(channelBuffer.readerIndex(), array); return array; } public String getString() { return getString(HttpConstants.DEFAULT_CHARSET); } public String getString(Charset encoding) { if (channelBuffer == null) { return ""; } if (encoding == null) { encoding = HttpConstants.DEFAULT_CHARSET; } return channelBuffer.toString(encoding); } /** * Utility to go from a In Memory FileUpload * to a Disk (or another implementation) FileUpload * @return the attached ChannelBuffer containing the actual bytes */ public ChannelBuffer getChannelBuffer() { return channelBuffer; } public ChannelBuffer getChunk(int length) throws IOException { if (channelBuffer == null || length == 0 || channelBuffer.readableBytes() == 0) { chunkPosition = 0; return ChannelBuffers.EMPTY_BUFFER; } int sizeLeft = channelBuffer.readableBytes() - chunkPosition; if (sizeLeft == 0) { chunkPosition = 0; return ChannelBuffers.EMPTY_BUFFER; } int sliceLength = length; if (sizeLeft < length) { sliceLength = sizeLeft; } ChannelBuffer chunk = channelBuffer.slice(chunkPosition, sliceLength); chunkPosition += sliceLength; return chunk; } public boolean isInMemory() { return true; } public boolean renameTo(File dest) throws IOException { if (dest == null) { throw new NullPointerException("dest"); } if (channelBuffer == null) { // empty file dest.createNewFile(); isRenamed = true; return true; } int length = channelBuffer.readableBytes(); FileOutputStream outputStream = new FileOutputStream(dest); FileChannel fileChannel = outputStream.getChannel(); ByteBuffer byteBuffer = channelBuffer.toByteBuffer(); int written = 0; while (written < length) { written += fileChannel.write(byteBuffer); } fileChannel.force(false); fileChannel.close(); outputStream.close(); isRenamed = true; return written == length; } public File getFile() throws IOException { throw new IOException("Not represented by a file"); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/Attribute.java000066400000000000000000000017601225554127700331030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import java.io.IOException; /** * Attribute interface */ public interface Attribute extends HttpData { /** * Returns the value of this HttpData. */ String getValue() throws IOException; /** * Sets the value of this HttpData. */ void setValue(String value) throws IOException; } DefaultHttpDataFactory.java000066400000000000000000000170341225554127700354300ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.handler.codec.http.HttpRequest; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** * Default factory giving Attribute and FileUpload according to constructor * * Attribute and FileUpload could be :
* - MemoryAttribute, DiskAttribute or MixedAttribute
* - MemoryFileUpload, DiskFileUpload or MixedFileUpload
* according to the constructor. */ public class DefaultHttpDataFactory implements HttpDataFactory { /** * Proposed default MINSIZE as 16 KB. */ public static final long MINSIZE = 0x4000; /** * Proposed default MAXSIZE = -1 as UNLIMITED */ public static final long MAXSIZE = -1; private final boolean useDisk; private final boolean checkSize; private long minSize; private long maxSize = MAXSIZE; /** * Keep all HttpDatas until cleanAllHttpDatas() is called. */ private final ConcurrentHashMap> requestFileDeleteMap = new ConcurrentHashMap>(); /** * HttpData will be in memory if less than default size (16KB). No limit setup. * The type will be Mixed. */ public DefaultHttpDataFactory() { useDisk = false; checkSize = true; minSize = MINSIZE; } /** * HttpData will be always on Disk if useDisk is True, else always in Memory if False. * No limit setup. */ public DefaultHttpDataFactory(boolean useDisk) { this.useDisk = useDisk; checkSize = false; } /** * HttpData will be on Disk if the size of the file is greater than minSize, else it * will be in memory. The type will be Mixed. No limit setup. */ public DefaultHttpDataFactory(long minSize) { useDisk = false; checkSize = true; this.minSize = minSize; } public void setMaxLimit(long max) { this.maxSize = max; } /** * @return the associated list of Files for the request */ private List getList(HttpRequest request) { List list = requestFileDeleteMap.get(request); if (list == null) { list = new ArrayList(); requestFileDeleteMap.put(request, list); } return list; } public Attribute createAttribute(HttpRequest request, String name) { if (useDisk) { Attribute attribute = new DiskAttribute(name); attribute.setMaxSize(maxSize); List fileToDelete = getList(request); fileToDelete.add(attribute); return attribute; } if (checkSize) { Attribute attribute = new MixedAttribute(name, minSize); attribute.setMaxSize(maxSize); List fileToDelete = getList(request); fileToDelete.add(attribute); return attribute; } MemoryAttribute attribute = new MemoryAttribute(name); attribute.setMaxSize(maxSize); return attribute; } /** * Utility method * @param data */ private void checkHttpDataSize(HttpData data) { try { data.checkSize(data.length()); } catch (IOException e) { throw new IllegalArgumentException("Attribute bigger than maxSize allowed"); } } public Attribute createAttribute(HttpRequest request, String name, String value) { if (useDisk) { Attribute attribute; try { attribute = new DiskAttribute(name, value); attribute.setMaxSize(maxSize); } catch (IOException e) { // revert to Mixed mode attribute = new MixedAttribute(name, value, minSize); attribute.setMaxSize(maxSize); } checkHttpDataSize(attribute); List fileToDelete = getList(request); fileToDelete.add(attribute); return attribute; } if (checkSize) { Attribute attribute = new MixedAttribute(name, value, minSize); attribute.setMaxSize(maxSize); checkHttpDataSize(attribute); List fileToDelete = getList(request); fileToDelete.add(attribute); return attribute; } try { MemoryAttribute attribute = new MemoryAttribute(name, value); attribute.setMaxSize(maxSize); checkHttpDataSize(attribute); return attribute; } catch (IOException e) { throw new IllegalArgumentException(e); } } public FileUpload createFileUpload(HttpRequest request, String name, String filename, String contentType, String contentTransferEncoding, Charset charset, long size) { if (useDisk) { FileUpload fileUpload = new DiskFileUpload(name, filename, contentType, contentTransferEncoding, charset, size); fileUpload.setMaxSize(maxSize); checkHttpDataSize(fileUpload); List fileToDelete = getList(request); fileToDelete.add(fileUpload); return fileUpload; } if (checkSize) { FileUpload fileUpload = new MixedFileUpload(name, filename, contentType, contentTransferEncoding, charset, size, minSize); fileUpload.setMaxSize(maxSize); checkHttpDataSize(fileUpload); List fileToDelete = getList(request); fileToDelete.add(fileUpload); return fileUpload; } MemoryFileUpload fileUpload = new MemoryFileUpload(name, filename, contentType, contentTransferEncoding, charset, size); fileUpload.setMaxSize(maxSize); checkHttpDataSize(fileUpload); return fileUpload; } public void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data) { if (data instanceof HttpData) { List fileToDelete = getList(request); fileToDelete.remove(data); } } public void cleanRequestHttpDatas(HttpRequest request) { List fileToDelete = requestFileDeleteMap.remove(request); if (fileToDelete != null) { for (HttpData data: fileToDelete) { data.delete(); } fileToDelete.clear(); } } public void cleanAllHttpDatas() { for (HttpRequest request : requestFileDeleteMap.keySet()) { List fileToDelete = requestFileDeleteMap.get(request); if (fileToDelete != null) { for (HttpData data: fileToDelete) { data.delete(); } fileToDelete.clear(); } requestFileDeleteMap.remove(request); } } } DiskAttribute.java000066400000000000000000000075411225554127700336420ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.HttpConstants; import java.io.IOException; /** * Disk implementation of Attributes */ public class DiskAttribute extends AbstractDiskHttpData implements Attribute { public static String baseDirectory; public static boolean deleteOnExitTemporaryFile = true; public static final String prefix = "Attr_"; public static final String postfix = ".att"; /** * Constructor used for huge Attribute */ public DiskAttribute(String name) { super(name, HttpConstants.DEFAULT_CHARSET, 0); } public DiskAttribute(String name, String value) throws IOException { super(name, HttpConstants.DEFAULT_CHARSET, 0); // Attribute have no default size setValue(value); } public HttpDataType getHttpDataType() { return HttpDataType.Attribute; } public String getValue() throws IOException { byte [] bytes = get(); return new String(bytes, charset.name()); } public void setValue(String value) throws IOException { if (value == null) { throw new NullPointerException("value"); } byte [] bytes = value.getBytes(charset.name()); checkSize(bytes.length); ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(bytes); if (definedSize > 0) { definedSize = buffer.readableBytes(); } setContent(buffer); } @Override public void addContent(ChannelBuffer buffer, boolean last) throws IOException { int localsize = buffer.readableBytes(); checkSize(size + localsize); if (definedSize > 0 && definedSize < size + localsize) { definedSize = size + localsize; } super.addContent(buffer, last); } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof Attribute)) { return false; } Attribute attribute = (Attribute) o; return getName().equalsIgnoreCase(attribute.getName()); } public int compareTo(InterfaceHttpData o) { if (!(o instanceof Attribute)) { throw new ClassCastException("Cannot compare " + getHttpDataType() + " with " + o.getHttpDataType()); } return compareTo((Attribute) o); } public int compareTo(Attribute o) { return getName().compareToIgnoreCase(o.getName()); } @Override public String toString() { try { return getName() + '=' + getValue(); } catch (IOException e) { return getName() + "=IoException"; } } @Override protected boolean deleteOnExit() { return deleteOnExitTemporaryFile; } @Override protected String getBaseDirectory() { return baseDirectory; } @Override protected String getDiskFilename() { return getName() + postfix; } @Override protected String getPostfix() { return postfix; } @Override protected String getPrefix() { return prefix; } } DiskFileUpload.java000066400000000000000000000107141225554127700337170ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.handler.codec.http.HttpHeaders; import java.io.File; import java.nio.charset.Charset; /** * Disk FileUpload implementation that stores file into real files */ public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload { public static String baseDirectory; public static boolean deleteOnExitTemporaryFile = true; public static final String prefix = "FUp_"; public static final String postfix = ".tmp"; private String filename; private String contentType; private String contentTransferEncoding; public DiskFileUpload(String name, String filename, String contentType, String contentTransferEncoding, Charset charset, long size) { super(name, charset, size); setFilename(filename); setContentType(contentType); setContentTransferEncoding(contentTransferEncoding); } public HttpDataType getHttpDataType() { return HttpDataType.FileUpload; } public String getFilename() { return filename; } public void setFilename(String filename) { if (filename == null) { throw new NullPointerException("filename"); } this.filename = filename; } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof Attribute)) { return false; } Attribute attribute = (Attribute) o; return getName().equalsIgnoreCase(attribute.getName()); } public int compareTo(InterfaceHttpData o) { if (!(o instanceof FileUpload)) { throw new ClassCastException("Cannot compare " + getHttpDataType() + " with " + o.getHttpDataType()); } return compareTo((FileUpload) o); } public int compareTo(FileUpload o) { int v; v = getName().compareToIgnoreCase(o.getName()); if (v != 0) { return v; } // TODO should we compare size ? return v; } public void setContentType(String contentType) { if (contentType == null) { throw new NullPointerException("contentType"); } this.contentType = contentType; } public String getContentType() { return contentType; } public String getContentTransferEncoding() { return contentTransferEncoding; } public void setContentTransferEncoding(String contentTransferEncoding) { this.contentTransferEncoding = contentTransferEncoding; } @Override public String toString() { return HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + getName() + "\"; " + HttpPostBodyUtil.FILENAME + "=\"" + filename + "\"\r\n" + HttpHeaders.Names.CONTENT_TYPE + ": " + contentType + (charset != null? "; " + HttpHeaders.Values.CHARSET + '=' + charset + "\r\n" : "\r\n") + HttpHeaders.Names.CONTENT_LENGTH + ": " + length() + "\r\n" + "Completed: " + isCompleted() + "\r\nIsInMemory: " + isInMemory() + "\r\nRealFile: " + file.getAbsolutePath() + " DefaultDeleteAfter: " + deleteOnExitTemporaryFile; } @Override protected boolean deleteOnExit() { return deleteOnExitTemporaryFile; } @Override protected String getBaseDirectory() { return baseDirectory; } @Override protected String getDiskFilename() { File file = new File(filename); return file.getName(); } @Override protected String getPostfix() { return postfix; } @Override protected String getPrefix() { return prefix; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/FileUpload.java000066400000000000000000000035541225554127700331670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; /** * FileUpload interface that could be in memory, on temporary file or any other implementations. * * Most methods are inspired from java.io.File API. */ public interface FileUpload extends HttpData { /** * Returns the original filename in the client's filesystem, * as provided by the browser (or other client software). * @return the original filename */ String getFilename(); /** * Set the original filename */ void setFilename(String filename); /** * Set the Content Type passed by the browser if defined * @param contentType Content Type to set - must be not null */ void setContentType(String contentType); /** * Returns the content type passed by the browser or null if not defined. * @return the content type passed by the browser or null if not defined. */ String getContentType(); /** * Set the Content-Transfer-Encoding type from String as 7bit, 8bit or binary */ void setContentTransferEncoding(String contentTransferEncoding); /** * Returns the Content-Transfer-Encoding * @return the Content-Transfer-Encoding */ String getContentTransferEncoding(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/HttpData.java000066400000000000000000000134051225554127700326500ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; /** * Extended interface for InterfaceHttpData */ public interface HttpData extends InterfaceHttpData { /** * Set the maxSize for this HttpData. When limit will be reached, an exception will be raised. * Setting it to (-1) means no limitation. * * By default, to be set from the HttpDataFactory. * @param maxSize */ void setMaxSize(long maxSize); /** * Check if the new size is not reaching the max limit allowed. * The limit is always computed in term of bytes. * @param newSize * @throws IOException */ void checkSize(long newSize) throws IOException; /** * Set the content from the ChannelBuffer (erase any previous data) * * @param buffer * must be not null * @exception IOException */ void setContent(ChannelBuffer buffer) throws IOException; /** * Add the content from the ChannelBuffer * * @param buffer * must be not null except if last is set to False * @param last * True of the buffer is the last one * @exception IOException */ void addContent(ChannelBuffer buffer, boolean last) throws IOException; /** * Set the content from the file (erase any previous data) * * @param file * must be not null * @exception IOException */ void setContent(File file) throws IOException; /** * Set the content from the inputStream (erase any previous data) * * @param inputStream * must be not null * @exception IOException */ void setContent(InputStream inputStream) throws IOException; /** * * @return True if the InterfaceHttpData is completed (all data are stored) */ boolean isCompleted(); /** * Returns the size in byte of the InterfaceHttpData * * @return the size of the InterfaceHttpData */ long length(); /** * Deletes the underlying storage for a file item, including deleting any * associated temporary disk file. */ void delete(); /** * Returns the contents of the file item as an array of bytes. * * @return the contents of the file item as an array of bytes. * @exception IOException */ byte[] get() throws IOException; /** * Returns the content of the file item as a ChannelBuffer * * @return the content of the file item as a ChannelBuffer * @throws IOException */ ChannelBuffer getChannelBuffer() throws IOException; /** * Returns a ChannelBuffer for the content from the current position with at * most length read bytes, increasing the current position of the Bytes * read. Once it arrives at the end, it returns an EMPTY_BUFFER and it * resets the current position to 0. * * @return a ChannelBuffer for the content from the current position or an * EMPTY_BUFFER if there is no more data to return */ ChannelBuffer getChunk(int length) throws IOException; /** * Returns the contents of the file item as a String, using the default * character encoding. * * @return the contents of the file item as a String, using the default * character encoding. */ String getString() throws IOException; /** * Returns the contents of the file item as a String, using the specified * charset. * * @param encoding * the charset to use * @return the contents of the file item as a String, using the specified * charset. * @exception IOException */ String getString(Charset encoding) throws IOException; /** * Set the Charset passed by the browser if defined * * @param charset * Charset to set - must be not null */ void setCharset(Charset charset); /** * Returns the Charset passed by the browser or null if not defined. * * @return the Charset passed by the browser or null if not defined. */ Charset getCharset(); /** * A convenience method to write an uploaded item to disk. If a previous one * exists, it will be deleted. Once this method is called, if successful, * the new file will be out of the cleaner of the factory that creates the * original InterfaceHttpData object. * * @param dest * destination file - must be not null * @return True if the write is successful * @exception IOException */ boolean renameTo(File dest) throws IOException; /** * Provides a hint as to whether or not the file contents will be read from * memory. * * @return True if the file contents is in memory. */ boolean isInMemory(); /** * * @return the associated File if this data is represented in a file * @exception IOException * if this data is not represented by a file */ File getFile() throws IOException; } HttpDataFactory.java000066400000000000000000000046521225554127700341250ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.handler.codec.http.HttpRequest; import java.nio.charset.Charset; /** * Interface to enable creation of InterfaceHttpData objects */ public interface HttpDataFactory { /** * To set a max size limitation on fields. Exceeding it will generate an ErrorDataDecoderException. * A value of -1 means no limitation (default). * @param max */ void setMaxLimit(long max); /** * * @param request associated request * @return a new Attribute with no value */ Attribute createAttribute(HttpRequest request, String name); /** * * @param request associated request * @return a new Attribute */ Attribute createAttribute(HttpRequest request, String name, String value); /** * @param request associated request * @param size the size of the Uploaded file * @return a new FileUpload */ FileUpload createFileUpload(HttpRequest request, String name, String filename, String contentType, String contentTransferEncoding, Charset charset, long size); /** * Remove the given InterfaceHttpData from clean list (will not delete the file, except if the file * is still a temporary one as setup at construction) * @param request associated request */ void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data); /** * Remove all InterfaceHttpData from virtual File storage from clean list for the request * * @param request associated request */ void cleanRequestHttpDatas(HttpRequest request); /** * Remove all InterfaceHttpData from virtual File storage from clean list for all requests */ void cleanAllHttpDatas(); } HttpPostBodyUtil.java000066400000000000000000000136351225554127700343260ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.util.CharsetUtil; import java.nio.charset.Charset; /** * Shared Static object between HttpMessageDecoder, HttpPostRequestDecoder and HttpPostRequestEncoder */ final class HttpPostBodyUtil { public static final int chunkSize = 8096; /** * HTTP content disposition header name. */ public static final String CONTENT_DISPOSITION = "Content-Disposition"; public static final String NAME = "name"; public static final String FILENAME = "filename"; /** * Content-disposition value for form data. */ public static final String FORM_DATA = "form-data"; /** * Content-disposition value for file attachment. */ public static final String ATTACHMENT = "attachment"; /** * Content-disposition value for file attachment. */ public static final String FILE = "file"; /** * HTTP content type body attribute for multiple uploads. */ public static final String MULTIPART_MIXED = "multipart/mixed"; /** * Charset for 8BIT */ public static final Charset ISO_8859_1 = CharsetUtil.ISO_8859_1; /** * Charset for 7BIT */ public static final Charset US_ASCII = CharsetUtil.US_ASCII; /** * Default Content-Type in binary form */ public static final String DEFAULT_BINARY_CONTENT_TYPE = "application/octet-stream"; /** * Default Content-Type in Text form */ public static final String DEFAULT_TEXT_CONTENT_TYPE = "text/plain"; /** * Allowed mechanism for multipart * mechanism := "7bit" / "8bit" / "binary" Not allowed: "quoted-printable" / "base64" */ public enum TransferEncodingMechanism { /** * Default encoding */ BIT7("7bit"), /** * Short lines but not in ASCII - no encoding */ BIT8("8bit"), /** * Could be long text not in ASCII - no encoding */ BINARY("binary"); private final String value; TransferEncodingMechanism(String value) { this.value = value; } TransferEncodingMechanism() { value = name(); } public String value() { return value; } @Override public String toString() { return value; } } private HttpPostBodyUtil() { } /** * Exception when NO Backend Array is found */ static class SeekAheadNoBackArrayException extends Exception { private static final long serialVersionUID = -630418804938699495L; } /** * This class intends to decrease the CPU in seeking ahead some bytes in * HttpPostRequestDecoder */ static class SeekAheadOptimize { byte[] bytes; int readerIndex; int pos; int origPos; int limit; ChannelBuffer buffer; SeekAheadOptimize(ChannelBuffer buffer) throws SeekAheadNoBackArrayException { if (!buffer.hasArray()) { throw new SeekAheadNoBackArrayException(); } this.buffer = buffer; bytes = buffer.array(); readerIndex = buffer.readerIndex(); origPos = pos = buffer.arrayOffset() + readerIndex; limit = buffer.arrayOffset() + buffer.writerIndex(); } /** * @param minus this value will be used as (currentPos - minus) to set * the current readerIndex in the buffer. */ void setReadPosition(int minus) { pos -= minus; readerIndex = getReadPosition(pos); buffer.readerIndex(readerIndex); } /** * * @param index raw index of the array (pos in general) * @return the value equivalent of raw index to be used in readerIndex(value) */ int getReadPosition(int index) { return index - origPos + readerIndex; } void clear() { buffer = null; bytes = null; limit = 0; pos = 0; readerIndex = 0; } } /** * Find the first non whitespace * @return the rank of the first non whitespace */ static int findNonWhitespace(String sb, int offset) { int result; for (result = offset; result < sb.length(); result ++) { if (!Character.isWhitespace(sb.charAt(result))) { break; } } return result; } /** * Find the first whitespace * @return the rank of the first whitespace */ static int findWhitespace(String sb, int offset) { int result; for (result = offset; result < sb.length(); result ++) { if (Character.isWhitespace(sb.charAt(result))) { break; } } return result; } /** * Find the end of String * @return the rank of the end of string */ static int findEndOfString(String sb) { int result; for (result = sb.length(); result > 0; result --) { if (!Character.isWhitespace(sb.charAt(result - 1))) { break; } } return result; } } HttpPostMultipartRequestDecoder.java000066400000000000000000002044221225554127700374070ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpConstants; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException; import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize; import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.TransferEncodingMechanism; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.IncompatibleDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.MultiPartStatus; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException; import org.jboss.netty.util.internal.CaseIgnoringComparator; import org.jboss.netty.util.internal.StringUtil; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * This decoder will decode Body and can handle POST BODY in multipart form. */ @SuppressWarnings({ "deprecation", "RedundantThrowsDeclaration" }) public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequestDecoder { /** * Factory used to create InterfaceHttpData */ private final HttpDataFactory factory; /** * Request to decode */ private final HttpRequest request; /** * Default charset to use */ private Charset charset; /** * Does the last chunk already received */ private boolean isLastChunk; /** * HttpDatas from Body */ private final List bodyListHttpData = new ArrayList(); /** * HttpDatas as Map from Body */ private final Map> bodyMapHttpData = new TreeMap>( CaseIgnoringComparator.INSTANCE); /** * The current channelBuffer */ private ChannelBuffer undecodedChunk; /** * Body HttpDatas current position */ private int bodyListHttpDataRank; /** * If multipart, this is the boundary for the flobal multipart */ private String multipartDataBoundary; /** * If multipart, there could be internal multiparts (mixed) to the global multipart. * Only one level is allowed. */ private String multipartMixedBoundary; /** * Current status */ private MultiPartStatus currentStatus = MultiPartStatus.NOTSTARTED; /** * Used in Multipart */ private Map currentFieldAttributes; /** * The current FileUpload that is currently in decode process */ private FileUpload currentFileUpload; /** * The current Attribute that is currently in decode process */ private Attribute currentAttribute; /** * * @param request the request to decode * @throws NullPointerException for request * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostMultipartRequestDecoder(HttpRequest request) throws ErrorDataDecoderException, IncompatibleDataDecoderException { this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to decode * @throws NullPointerException for request or factory * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostMultipartRequestDecoder(HttpDataFactory factory, HttpRequest request) throws ErrorDataDecoderException, IncompatibleDataDecoderException { this(factory, request, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to decode * @param charset the charset to use as default * @throws NullPointerException for request or charset or factory * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostMultipartRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) throws ErrorDataDecoderException, IncompatibleDataDecoderException { if (factory == null) { throw new NullPointerException("factory"); } if (request == null) { throw new NullPointerException("request"); } if (charset == null) { throw new NullPointerException("charset"); } this.request = request; this.charset = charset; this.factory = factory; // Fill default values setMultipart(this.request.headers().get(HttpHeaders.Names.CONTENT_TYPE)); if (!this.request.isChunked()) { undecodedChunk = this.request.getContent(); isLastChunk = true; parseBody(); } } /** * Set from the request ContentType the multipartDataBoundary and the possible charset. */ private void setMultipart(String contentType) throws ErrorDataDecoderException { String[] dataBoundary = HttpPostRequestDecoder.getMultipartDataBoundary(contentType); if (dataBoundary != null) { multipartDataBoundary = dataBoundary[0]; if (dataBoundary.length > 1 && dataBoundary[1] != null) { charset = Charset.forName(dataBoundary[1]); } } else { multipartDataBoundary = null; } currentStatus = MultiPartStatus.HEADERDELIMITER; } public boolean isMultipart() { return true; } public List getBodyHttpDatas() throws NotEnoughDataDecoderException { if (!isLastChunk) { throw new NotEnoughDataDecoderException(); } return bodyListHttpData; } public List getBodyHttpDatas(String name) throws NotEnoughDataDecoderException { if (!isLastChunk) { throw new NotEnoughDataDecoderException(); } return bodyMapHttpData.get(name); } public InterfaceHttpData getBodyHttpData(String name) throws NotEnoughDataDecoderException { if (!isLastChunk) { throw new NotEnoughDataDecoderException(); } List list = bodyMapHttpData.get(name); if (list != null) { return list.get(0); } return null; } public void offer(HttpChunk chunk) throws ErrorDataDecoderException { ChannelBuffer chunked = chunk.getContent(); if (undecodedChunk == null) { undecodedChunk = chunked; } else { //undecodedChunk = ChannelBuffers.wrappedBuffer(undecodedChunk, chunk.getContent()); // less memory usage undecodedChunk = ChannelBuffers.wrappedBuffer( undecodedChunk, chunked); } if (chunk.isLast()) { isLastChunk = true; } parseBody(); } public boolean hasNext() throws EndOfDataDecoderException { if (currentStatus == MultiPartStatus.EPILOGUE) { // OK except if end of list if (bodyListHttpDataRank >= bodyListHttpData.size()) { throw new EndOfDataDecoderException(); } } return !bodyListHttpData.isEmpty() && bodyListHttpDataRank < bodyListHttpData.size(); } public InterfaceHttpData next() throws EndOfDataDecoderException { if (hasNext()) { return bodyListHttpData.get(bodyListHttpDataRank++); } return null; } /** * This method will parse as much as possible data and fill the list and map * @throws ErrorDataDecoderException if there is a problem with the charset decoding or * other errors */ private void parseBody() throws ErrorDataDecoderException { if (currentStatus == MultiPartStatus.PREEPILOGUE || currentStatus == MultiPartStatus.EPILOGUE) { if (isLastChunk) { currentStatus = MultiPartStatus.EPILOGUE; } return; } parseBodyMultipart(); } /** * Utility function to add a new decoded data */ private void addHttpData(InterfaceHttpData data) { if (data == null) { return; } List datas = bodyMapHttpData.get(data.getName()); if (datas == null) { datas = new ArrayList(1); bodyMapHttpData.put(data.getName(), datas); } datas.add(data); bodyListHttpData.add(data); } /** * Parse the Body for multipart * * @throws ErrorDataDecoderException if there is a problem with the charset decoding or other errors */ private void parseBodyMultipart() throws ErrorDataDecoderException { if (undecodedChunk == null || undecodedChunk.readableBytes() == 0) { // nothing to decode return; } InterfaceHttpData data = decodeMultipart(currentStatus); while (data != null) { addHttpData(data); if (currentStatus == MultiPartStatus.PREEPILOGUE || currentStatus == MultiPartStatus.EPILOGUE) { break; } data = decodeMultipart(currentStatus); } } /** * Decode a multipart request by pieces
*
* NOTSTARTED PREAMBLE (
* (HEADERDELIMITER DISPOSITION (FIELD | FILEUPLOAD))*
* (HEADERDELIMITER DISPOSITION MIXEDPREAMBLE
* (MIXEDDELIMITER MIXEDDISPOSITION MIXEDFILEUPLOAD)+
* MIXEDCLOSEDELIMITER)*
* CLOSEDELIMITER)+ EPILOGUE
* * Inspired from HttpMessageDecoder * * @return the next decoded InterfaceHttpData or null if none until now. * @throws ErrorDataDecoderException if an error occurs */ private InterfaceHttpData decodeMultipart(MultiPartStatus state) throws ErrorDataDecoderException { switch (state) { case NOTSTARTED: throw new ErrorDataDecoderException( "Should not be called with the current status"); case PREAMBLE: // Content-type: multipart/form-data, boundary=AaB03x throw new ErrorDataDecoderException( "Should not be called with the current status"); case HEADERDELIMITER: { // --AaB03x or --AaB03x-- return findMultipartDelimiter(multipartDataBoundary, MultiPartStatus.DISPOSITION, MultiPartStatus.PREEPILOGUE); } case DISPOSITION: { // content-disposition: form-data; name="field1" // content-disposition: form-data; name="pics"; filename="file1.txt" // and other immediate values like // Content-type: image/gif // Content-Type: text/plain // Content-Type: text/plain; charset=ISO-8859-1 // Content-Transfer-Encoding: binary // The following line implies a change of mode (mixed mode) // Content-type: multipart/mixed, boundary=BbC04y return findMultipartDisposition(); } case FIELD: { // Now get value according to Content-Type and Charset Charset localCharset = null; Attribute charsetAttribute = currentFieldAttributes .get(HttpHeaders.Values.CHARSET); if (charsetAttribute != null) { try { localCharset = Charset.forName(charsetAttribute.getValue()); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } Attribute nameAttribute = currentFieldAttributes .get(HttpPostBodyUtil.NAME); if (currentAttribute == null) { try { currentAttribute = factory.createAttribute(request, cleanString(nameAttribute.getValue())); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } catch (IOException e) { throw new ErrorDataDecoderException(e); } if (localCharset != null) { currentAttribute.setCharset(localCharset); } } // load data try { loadFieldMultipart(multipartDataBoundary); } catch (NotEnoughDataDecoderException e) { return null; } Attribute finalAttribute = currentAttribute; currentAttribute = null; currentFieldAttributes = null; // ready to load the next one currentStatus = MultiPartStatus.HEADERDELIMITER; return finalAttribute; } case FILEUPLOAD: { // eventually restart from existing FileUpload return getFileUpload(multipartDataBoundary); } case MIXEDDELIMITER: { // --AaB03x or --AaB03x-- // Note that currentFieldAttributes exists return findMultipartDelimiter(multipartMixedBoundary, MultiPartStatus.MIXEDDISPOSITION, MultiPartStatus.HEADERDELIMITER); } case MIXEDDISPOSITION: { return findMultipartDisposition(); } case MIXEDFILEUPLOAD: { // eventually restart from existing FileUpload return getFileUpload(multipartMixedBoundary); } case PREEPILOGUE: return null; case EPILOGUE: return null; default: throw new ErrorDataDecoderException("Shouldn't reach here."); } } /** * Skip control Characters * @throws NotEnoughDataDecoderException */ void skipControlCharacters() throws NotEnoughDataDecoderException { SeekAheadOptimize sao; try { sao = new SeekAheadOptimize(undecodedChunk); } catch (SeekAheadNoBackArrayException e) { try { skipControlCharactersStandard(); } catch (IndexOutOfBoundsException e1) { throw new NotEnoughDataDecoderException(e1); } return; } while (sao.pos < sao.limit) { char c = (char) (sao.bytes[sao.pos ++] & 0xFF); if (!Character.isISOControl(c) && !Character.isWhitespace(c)) { sao.setReadPosition(1); return; } } throw new NotEnoughDataDecoderException("Access out of bounds"); } void skipControlCharactersStandard() { for (;;) { char c = (char) undecodedChunk.readUnsignedByte(); if (!Character.isISOControl(c) && !Character.isWhitespace(c)) { undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1); break; } } } /** * Find the next Multipart Delimiter * @param delimiter delimiter to find * @param dispositionStatus the next status if the delimiter is a start * @param closeDelimiterStatus the next status if the delimiter is a close delimiter * @return the next InterfaceHttpData if any * @throws ErrorDataDecoderException */ private InterfaceHttpData findMultipartDelimiter(String delimiter, MultiPartStatus dispositionStatus, MultiPartStatus closeDelimiterStatus) throws ErrorDataDecoderException { // --AaB03x or --AaB03x-- int readerIndex = undecodedChunk.readerIndex(); try { skipControlCharacters(); } catch (NotEnoughDataDecoderException e1) { undecodedChunk.readerIndex(readerIndex); return null; } skipOneLine(); String newline; try { newline = readDelimiter(delimiter); } catch (NotEnoughDataDecoderException e) { undecodedChunk.readerIndex(readerIndex); return null; } if (newline.equals(delimiter)) { currentStatus = dispositionStatus; return decodeMultipart(dispositionStatus); } if (newline.equals(delimiter + "--")) { // CLOSEDELIMITER or MIXED CLOSEDELIMITER found currentStatus = closeDelimiterStatus; if (currentStatus == MultiPartStatus.HEADERDELIMITER) { // MIXEDCLOSEDELIMITER // end of the Mixed part currentFieldAttributes = null; return decodeMultipart(MultiPartStatus.HEADERDELIMITER); } return null; } undecodedChunk.readerIndex(readerIndex); throw new ErrorDataDecoderException("No Multipart delimiter found"); } /** * Find the next Disposition * @return the next InterfaceHttpData if any * @throws ErrorDataDecoderException */ private InterfaceHttpData findMultipartDisposition() throws ErrorDataDecoderException { int readerIndex = undecodedChunk.readerIndex(); if (currentStatus == MultiPartStatus.DISPOSITION) { currentFieldAttributes = new TreeMap( CaseIgnoringComparator.INSTANCE); } // read many lines until empty line with newline found! Store all data while (!skipOneLine()) { String newline; try { skipControlCharacters(); newline = readLine(); } catch (NotEnoughDataDecoderException e) { undecodedChunk.readerIndex(readerIndex); return null; } String[] contents = splitMultipartHeader(newline); if (contents[0].equalsIgnoreCase(HttpPostBodyUtil.CONTENT_DISPOSITION)) { boolean checkSecondArg; if (currentStatus == MultiPartStatus.DISPOSITION) { checkSecondArg = contents[1] .equalsIgnoreCase(HttpPostBodyUtil.FORM_DATA); } else { checkSecondArg = contents[1] .equalsIgnoreCase(HttpPostBodyUtil.ATTACHMENT) || contents[1] .equalsIgnoreCase(HttpPostBodyUtil.FILE); } if (checkSecondArg) { // read next values and store them in the map as Attribute for (int i = 2; i < contents.length; i ++) { String[] values = StringUtil.split(contents[i], '='); Attribute attribute; try { String name = cleanString(values[0]); String value = values[1]; // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html if (HttpPostBodyUtil.FILENAME.equals(name)) { // filename value is quoted string so strip them value = value.substring(1, value.length() - 1); } else { // otherwise we need to clean the value value = cleanString(value); } attribute = factory.createAttribute(request, name, value); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } currentFieldAttributes.put(attribute.getName(), attribute); } } } else if (contents[0] .equalsIgnoreCase(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING)) { Attribute attribute; try { attribute = factory.createAttribute(request, HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, cleanString(contents[1])); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } currentFieldAttributes.put( HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, attribute); } else if (contents[0] .equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH)) { Attribute attribute; try { attribute = factory.createAttribute(request, HttpHeaders.Names.CONTENT_LENGTH, cleanString(contents[1])); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } currentFieldAttributes.put(HttpHeaders.Names.CONTENT_LENGTH, attribute); } else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_TYPE)) { // Take care of possible "multipart/mixed" if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) { if (currentStatus == MultiPartStatus.DISPOSITION) { String[] values = StringUtil.split(contents[2], '='); multipartMixedBoundary = "--" + values[1]; currentStatus = MultiPartStatus.MIXEDDELIMITER; return decodeMultipart(MultiPartStatus.MIXEDDELIMITER); } else { throw new ErrorDataDecoderException( "Mixed Multipart found in a previous Mixed Multipart"); } } else { for (int i = 1; i < contents.length; i ++) { if (contents[i].toLowerCase().startsWith( HttpHeaders.Values.CHARSET)) { String[] values = StringUtil.split(contents[i], '='); Attribute attribute; try { attribute = factory.createAttribute(request, HttpHeaders.Values.CHARSET, cleanString(values[1])); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } currentFieldAttributes.put(HttpHeaders.Values.CHARSET, attribute); } else { Attribute attribute; try { attribute = factory.createAttribute(request, cleanString(contents[0]), contents[i]); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } currentFieldAttributes.put(attribute.getName(), attribute); } } } } else { throw new ErrorDataDecoderException("Unknown Params: " + newline); } } // Is it a FileUpload Attribute filenameAttribute = currentFieldAttributes .get(HttpPostBodyUtil.FILENAME); if (currentStatus == MultiPartStatus.DISPOSITION) { if (filenameAttribute != null) { // FileUpload currentStatus = MultiPartStatus.FILEUPLOAD; // do not change the buffer position return decodeMultipart(MultiPartStatus.FILEUPLOAD); } else { // Field currentStatus = MultiPartStatus.FIELD; // do not change the buffer position return decodeMultipart(MultiPartStatus.FIELD); } } else { if (filenameAttribute != null) { // FileUpload currentStatus = MultiPartStatus.MIXEDFILEUPLOAD; // do not change the buffer position return decodeMultipart(MultiPartStatus.MIXEDFILEUPLOAD); } else { // Field is not supported in MIXED mode throw new ErrorDataDecoderException("Filename not found"); } } } /** * Get the FileUpload (new one or current one) * @param delimiter the delimiter to use * @return the InterfaceHttpData if any * @throws ErrorDataDecoderException */ private InterfaceHttpData getFileUpload(String delimiter) throws ErrorDataDecoderException { // eventually restart from existing FileUpload // Now get value according to Content-Type and Charset Attribute encoding = currentFieldAttributes .get(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING); Charset localCharset = charset; // Default TransferEncodingMechanism mechanism = TransferEncodingMechanism.BIT7; if (encoding != null) { String code; try { code = encoding.getValue().toLowerCase(); } catch (IOException e) { throw new ErrorDataDecoderException(e); } if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BIT7.value())) { localCharset = HttpPostBodyUtil.US_ASCII; } else if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BIT8.value())) { localCharset = HttpPostBodyUtil.ISO_8859_1; mechanism = TransferEncodingMechanism.BIT8; } else if (code .equals(HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value())) { // no real charset, so let the default mechanism = TransferEncodingMechanism.BINARY; } else { throw new ErrorDataDecoderException( "TransferEncoding Unknown: " + code); } } Attribute charsetAttribute = currentFieldAttributes .get(HttpHeaders.Values.CHARSET); if (charsetAttribute != null) { try { localCharset = Charset.forName(charsetAttribute.getValue()); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } if (currentFileUpload == null) { Attribute filenameAttribute = currentFieldAttributes .get(HttpPostBodyUtil.FILENAME); Attribute nameAttribute = currentFieldAttributes .get(HttpPostBodyUtil.NAME); Attribute contentTypeAttribute = currentFieldAttributes .get(HttpHeaders.Names.CONTENT_TYPE); if (contentTypeAttribute == null) { // instead of raising an exception, create a default Content-Type contentTypeAttribute = new MemoryAttribute(HttpHeaders.Names.CONTENT_TYPE); try { contentTypeAttribute.setValue(HttpPostBodyUtil.DEFAULT_BINARY_CONTENT_TYPE); } catch (IOException e) { throw new ErrorDataDecoderException( "Content-Type is absent but required, and cannot be reverted to default"); } } Attribute lengthAttribute = currentFieldAttributes .get(HttpHeaders.Names.CONTENT_LENGTH); long size; try { size = lengthAttribute != null? Long.parseLong(lengthAttribute .getValue()) : 0L; } catch (IOException e) { throw new ErrorDataDecoderException(e); } catch (NumberFormatException e) { size = 0; } try { currentFileUpload = factory.createFileUpload( request, cleanString(nameAttribute.getValue()), cleanString(filenameAttribute.getValue()), contentTypeAttribute.getValue(), mechanism.value(), localCharset, size); } catch (NullPointerException e) { throw new ErrorDataDecoderException(e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException(e); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } // load data as much as possible try { readFileUploadByteMultipart(delimiter); } catch (NotEnoughDataDecoderException e) { // do not change the buffer position // since some can be already saved into FileUpload // So do not change the currentStatus return null; } if (currentFileUpload.isCompleted()) { // ready to load the next one if (currentStatus == MultiPartStatus.FILEUPLOAD) { currentStatus = MultiPartStatus.HEADERDELIMITER; currentFieldAttributes = null; } else { currentStatus = MultiPartStatus.MIXEDDELIMITER; cleanMixedAttributes(); } FileUpload fileUpload = currentFileUpload; currentFileUpload = null; return fileUpload; } // do not change the buffer position // since some can be already saved into FileUpload // So do not change the currentStatus return null; } public void cleanFiles() { factory.cleanRequestHttpDatas(request); } public void removeHttpDataFromClean(InterfaceHttpData data) { factory.removeHttpDataFromClean(request, data); } /** * Remove all Attributes that should be cleaned between two FileUpload in Mixed mode */ private void cleanMixedAttributes() { currentFieldAttributes.remove(HttpHeaders.Values.CHARSET); currentFieldAttributes.remove(HttpHeaders.Names.CONTENT_LENGTH); currentFieldAttributes.remove(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING); currentFieldAttributes.remove(HttpHeaders.Names.CONTENT_TYPE); currentFieldAttributes.remove(HttpPostBodyUtil.FILENAME); } /** * Read one line up to the CRLF or LF * @return the String from one line * @throws NotEnoughDataDecoderException Need more chunks and * reset the readerInder to the previous value */ private String readLineStandard() throws NotEnoughDataDecoderException { int readerIndex = undecodedChunk.readerIndex(); try { ChannelBuffer line = ChannelBuffers.dynamicBuffer(64); while (undecodedChunk.readable()) { byte nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.CR) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { return line.toString(charset); } } else if (nextByte == HttpConstants.LF) { return line.toString(charset); } else { line.writeByte(nextByte); } } } catch (IndexOutOfBoundsException e) { undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(e); } undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } /** * Read one line up to the CRLF or LF * @return the String from one line * @throws NotEnoughDataDecoderException Need more chunks and * reset the readerInder to the previous value */ private String readLine() throws NotEnoughDataDecoderException { SeekAheadOptimize sao; try { sao = new SeekAheadOptimize(undecodedChunk); } catch (SeekAheadNoBackArrayException e1) { return readLineStandard(); } int readerIndex = undecodedChunk.readerIndex(); try { ChannelBuffer line = ChannelBuffers.dynamicBuffer(64); while (sao.pos < sao.limit) { byte nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.CR) { if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.LF) { sao.setReadPosition(0); return line.toString(charset); } } else { line.writeByte(nextByte); } } else if (nextByte == HttpConstants.LF) { sao.setReadPosition(0); return line.toString(charset); } else { line.writeByte(nextByte); } } } catch (IndexOutOfBoundsException e) { undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(e); } undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } /** * Read one line up to --delimiter or --delimiter-- and if existing the CRLF or LF * Read one line up to --delimiter or --delimiter-- and if existing the CRLF or LF. * Note that CRLF or LF are mandatory for opening delimiter (--delimiter) but not for * closing delimiter (--delimiter--) since some clients does not include CRLF in this case. * * @param delimiter of the form --string, such that '--' is already included * @return the String from one line as the delimiter searched (opening or closing) * @throws NotEnoughDataDecoderException Need more chunks and * reset the readerInder to the previous value */ private String readDelimiterStandard(String delimiter) throws NotEnoughDataDecoderException { int readerIndex = undecodedChunk.readerIndex(); try { StringBuilder sb = new StringBuilder(64); int delimiterPos = 0; int len = delimiter.length(); while (undecodedChunk.readable() && delimiterPos < len) { byte nextByte = undecodedChunk.readByte(); if (nextByte == delimiter.charAt(delimiterPos)) { delimiterPos++; sb.append((char) nextByte); } else { // delimiter not found so break here ! undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } } // Now check if either opening delimiter or closing delimiter if (undecodedChunk.readable()) { byte nextByte = undecodedChunk.readByte(); // first check for opening delimiter if (nextByte == HttpConstants.CR) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { return sb.toString(); } else { // error since CR must be followed by LF // delimiter not found so break here ! undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } } else if (nextByte == HttpConstants.LF) { return sb.toString(); } else if (nextByte == '-') { sb.append('-'); // second check for closing delimiter nextByte = undecodedChunk.readByte(); if (nextByte == '-') { sb.append('-'); // now try to find if CRLF or LF there if (undecodedChunk.readable()) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.CR) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { return sb.toString(); } else { // error CR without LF // delimiter not found so break here ! undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } } else if (nextByte == HttpConstants.LF) { return sb.toString(); } else { // No CRLF but ok however (Adobe Flash uploader) // minus 1 since we read one char ahead but should not undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1); return sb.toString(); } } // FIXME what do we do here? // either considering it is fine, either waiting for more data to come? // lets try considering it is fine... return sb.toString(); } // only one '-' => not enough // whatever now => error since incomplete } } } catch (IndexOutOfBoundsException e) { undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(e); } undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } /** * Read one line up to --delimiter or --delimiter-- and if existing the CRLF or LF. * Note that CRLF or LF are mandatory for opening delimiter (--delimiter) but not for * closing delimiter (--delimiter--) since some clients does not include CRLF in this case. * * @param delimiter of the form --string, such that '--' is already included * @return the String from one line as the delimiter searched (opening or closing) * @throws NotEnoughDataDecoderException Need more chunks and * reset the readerInder to the previous value */ private String readDelimiter(String delimiter) throws NotEnoughDataDecoderException { SeekAheadOptimize sao; try { sao = new SeekAheadOptimize(undecodedChunk); } catch (SeekAheadNoBackArrayException e1) { return readDelimiterStandard(delimiter); } int readerIndex = undecodedChunk.readerIndex(); int delimiterPos = 0; int len = delimiter.length(); try { StringBuilder sb = new StringBuilder(64); // check conformity with delimiter while (sao.pos < sao.limit && delimiterPos < len) { byte nextByte = sao.bytes[sao.pos ++]; if (nextByte == delimiter.charAt(delimiterPos)) { delimiterPos++; sb.append((char) nextByte); } else { // delimiter not found so break here ! undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } } // Now check if either opening delimiter or closing delimiter if (sao.pos < sao.limit) { byte nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.CR) { // first check for opening delimiter if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.LF) { sao.setReadPosition(0); return sb.toString(); } } else { // error since CR must be followed by LF // delimiter not found so break here ! undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } } else if (nextByte == HttpConstants.LF) { // same first check for opening delimiter where LF used with no CR sao.setReadPosition(0); return sb.toString(); } else if (nextByte == '-') { sb.append('-'); // second check for closing delimiter if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == '-') { sb.append('-'); // now try to find if CRLF or LF there if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos++]; if (nextByte == HttpConstants.CR) { if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos++]; if (nextByte == HttpConstants.LF) { sao.setReadPosition(0); return sb.toString(); } } else { // error CR without LF // delimiter not found so break here ! undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } } else if (nextByte == HttpConstants.LF) { sao.setReadPosition(0); return sb.toString(); } else { // No CRLF but ok however (Adobe Flash uploader) // minus 1 since we read one char ahead but should not sao.setReadPosition(1); return sb.toString(); } } // FIXME what do we do here? // either considering it is fine, either waiting for more data to come? // lets try considering it is fine... sao.setReadPosition(0); return sb.toString(); } // whatever now => error since incomplete // only one '-' => not enough or whatever not enough element } } } } catch (IndexOutOfBoundsException e) { undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(e); } undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(); } /** * Read a FileUpload data as Byte (Binary) and add the bytes directly to the * FileUpload. If the delimiter is found, the FileUpload is completed. * @throws NotEnoughDataDecoderException Need more chunks but * do not reset the readerInder since some values will be already added to the FileOutput * @throws ErrorDataDecoderException write IO error occurs with the FileUpload */ private void readFileUploadByteMultipartStandard(String delimiter) throws NotEnoughDataDecoderException, ErrorDataDecoderException { int readerIndex = undecodedChunk.readerIndex(); // found the decoder limit boolean newLine = true; int index = 0; int lastPosition = undecodedChunk.readerIndex(); boolean found = false; while (undecodedChunk.readable()) { byte nextByte = undecodedChunk.readByte(); if (newLine) { // Check the delimiter if (nextByte == delimiter.codePointAt(index)) { index ++; if (delimiter.length() == index) { found = true; break; } continue; } else { newLine = false; index = 0; // continue until end of line if (nextByte == HttpConstants.CR) { if (undecodedChunk.readable()) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 2; } else { // save last valid position lastPosition = undecodedChunk.readerIndex() - 1; // Unread next byte. undecodedChunk.readerIndex(lastPosition); } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 1; } else { // save last valid position lastPosition = undecodedChunk.readerIndex(); } } } else { // continue until end of line if (nextByte == HttpConstants.CR) { if (undecodedChunk.readable()) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 2; } else { // save last valid position lastPosition = undecodedChunk.readerIndex() - 1; // Unread next byte. undecodedChunk.readerIndex(lastPosition); } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 1; } else { // save last valid position lastPosition = undecodedChunk.readerIndex(); } } } ChannelBuffer buffer = undecodedChunk.slice(readerIndex, lastPosition - readerIndex); if (found) { // found so lastPosition is correct and final try { currentFileUpload.addContent(buffer, true); // just before the CRLF and delimiter undecodedChunk.readerIndex(lastPosition); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } else { // possibly the delimiter is partially found but still the last position is OK try { currentFileUpload.addContent(buffer, false); // last valid char (not CR, not LF, not beginning of delimiter) undecodedChunk.readerIndex(lastPosition); throw new NotEnoughDataDecoderException(); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } } /** * Read a FileUpload data as Byte (Binary) and add the bytes directly to the * FileUpload. If the delimiter is found, the FileUpload is completed. * @throws NotEnoughDataDecoderException Need more chunks but * do not reset the readerInder since some values will be already added to the FileOutput * @throws ErrorDataDecoderException write IO error occurs with the FileUpload */ private void readFileUploadByteMultipart(String delimiter) throws NotEnoughDataDecoderException, ErrorDataDecoderException { SeekAheadOptimize sao; try { sao = new SeekAheadOptimize(undecodedChunk); } catch (SeekAheadNoBackArrayException e1) { readFileUploadByteMultipartStandard(delimiter); return; } int readerIndex = undecodedChunk.readerIndex(); // found the decoder limit boolean newLine = true; int index = 0; int lastrealpos = sao.pos; int lastPosition; boolean found = false; while (sao.pos < sao.limit) { byte nextByte = sao.bytes[sao.pos ++]; if (newLine) { // Check the delimiter if (nextByte == delimiter.codePointAt(index)) { index ++; if (delimiter.length() == index) { found = true; break; } continue; } else { newLine = false; index = 0; // continue until end of line if (nextByte == HttpConstants.CR) { if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 2; } else { // unread next byte sao.pos--; // save last valid position lastrealpos = sao.pos; } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 1; } else { // save last valid position lastrealpos = sao.pos; } } } else { // continue until end of line if (nextByte == HttpConstants.CR) { if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 2; } else { // unread next byte sao.pos--; // save last valid position lastrealpos = sao.pos; } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 1; } else { // save last valid position lastrealpos = sao.pos; } } } lastPosition = sao.getReadPosition(lastrealpos); ChannelBuffer buffer = undecodedChunk.slice(readerIndex, lastPosition - readerIndex); if (found) { // found so lastPosition is correct and final try { currentFileUpload.addContent(buffer, true); // just before the CRLF and delimiter undecodedChunk.readerIndex(lastPosition); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } else { // possibly the delimiter is partially found but still the last position is OK try { currentFileUpload.addContent(buffer, false); // last valid char (not CR, not LF, not beginning of delimiter) undecodedChunk.readerIndex(lastPosition); throw new NotEnoughDataDecoderException(); } catch (IOException e) { throw new ErrorDataDecoderException(e); } } } /** * Load the field value from a Multipart request * @throws NotEnoughDataDecoderException Need more chunks * @throws ErrorDataDecoderException */ private void loadFieldMultipartStandard(String delimiter) throws NotEnoughDataDecoderException, ErrorDataDecoderException { int readerIndex = undecodedChunk.readerIndex(); try { // found the decoder limit boolean newLine = true; int index = 0; int lastPosition = undecodedChunk.readerIndex(); boolean found = false; while (undecodedChunk.readable()) { byte nextByte = undecodedChunk.readByte(); if (newLine) { // Check the delimiter if (nextByte == delimiter.codePointAt(index)) { index ++; if (delimiter.length() == index) { found = true; break; } continue; } else { newLine = false; index = 0; // continue until end of line if (nextByte == HttpConstants.CR) { if (undecodedChunk.readable()) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 2; } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 1; } else { lastPosition = undecodedChunk.readerIndex(); } } } else { // continue until end of line if (nextByte == HttpConstants.CR) { if (undecodedChunk.readable()) { nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 2; } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastPosition = undecodedChunk.readerIndex() - 1; } else { lastPosition = undecodedChunk.readerIndex(); } } } if (found) { // found so lastPosition is correct // but position is just after the delimiter (either close delimiter or simple one) // so go back of delimiter size try { currentAttribute.addContent( undecodedChunk.slice(readerIndex, lastPosition - readerIndex), true); } catch (IOException e) { throw new ErrorDataDecoderException(e); } undecodedChunk.readerIndex(lastPosition); } else { try { currentAttribute.addContent( undecodedChunk.slice(readerIndex, lastPosition - readerIndex), false); } catch (IOException e) { throw new ErrorDataDecoderException(e); } undecodedChunk.readerIndex(lastPosition); throw new NotEnoughDataDecoderException(); } } catch (IndexOutOfBoundsException e) { undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(e); } } /** * Load the field value from a Multipart request * @throws NotEnoughDataDecoderException Need more chunks * @throws ErrorDataDecoderException */ private void loadFieldMultipart(String delimiter) throws NotEnoughDataDecoderException, ErrorDataDecoderException { SeekAheadOptimize sao; try { sao = new SeekAheadOptimize(undecodedChunk); } catch (SeekAheadNoBackArrayException e1) { loadFieldMultipartStandard(delimiter); return; } int readerIndex = undecodedChunk.readerIndex(); try { // found the decoder limit boolean newLine = true; int index = 0; int lastPosition; int lastrealpos = sao.pos; boolean found = false; while (sao.pos < sao.limit) { byte nextByte = sao.bytes[sao.pos ++]; if (newLine) { // Check the delimiter if (nextByte == delimiter.codePointAt(index)) { index ++; if (delimiter.length() == index) { found = true; break; } continue; } else { newLine = false; index = 0; // continue until end of line if (nextByte == HttpConstants.CR) { if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 2; } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 1; } else { lastrealpos = sao.pos; } } } else { // continue until end of line if (nextByte == HttpConstants.CR) { if (sao.pos < sao.limit) { nextByte = sao.bytes[sao.pos ++]; if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 2; } } } else if (nextByte == HttpConstants.LF) { newLine = true; index = 0; lastrealpos = sao.pos - 1; } else { lastrealpos = sao.pos; } } } lastPosition = sao.getReadPosition(lastrealpos); if (found) { // found so lastPosition is correct // but position is just after the delimiter (either close delimiter or simple one) // so go back of delimiter size try { currentAttribute.addContent( undecodedChunk.slice(readerIndex, lastPosition - readerIndex), true); } catch (IOException e) { throw new ErrorDataDecoderException(e); } undecodedChunk.readerIndex(lastPosition); } else { try { currentAttribute.addContent( undecodedChunk.slice(readerIndex, lastPosition - readerIndex), false); } catch (IOException e) { throw new ErrorDataDecoderException(e); } undecodedChunk.readerIndex(lastPosition); throw new NotEnoughDataDecoderException(); } } catch (IndexOutOfBoundsException e) { undecodedChunk.readerIndex(readerIndex); throw new NotEnoughDataDecoderException(e); } } /** * Clean the String from any unallowed character * @return the cleaned String */ private static String cleanString(String field) { StringBuilder sb = new StringBuilder(field.length()); for (int i = 0; i < field.length(); i ++) { char nextChar = field.charAt(i); if (nextChar == HttpConstants.COLON) { sb.append(HttpConstants.SP); } else if (nextChar == HttpConstants.COMMA) { sb.append(HttpConstants.SP); } else if (nextChar == HttpConstants.EQUALS) { sb.append(HttpConstants.SP); } else if (nextChar == HttpConstants.SEMICOLON) { sb.append(HttpConstants.SP); } else if (nextChar == HttpConstants.HT) { sb.append(HttpConstants.SP); } else if (nextChar == HttpConstants.DOUBLE_QUOTE) { // nothing added, just removes it } else { sb.append(nextChar); } } return sb.toString().trim(); } /** * Skip one empty line * @return True if one empty line was skipped */ private boolean skipOneLine() { if (!undecodedChunk.readable()) { return false; } byte nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.CR) { if (!undecodedChunk.readable()) { undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1); return false; } nextByte = undecodedChunk.readByte(); if (nextByte == HttpConstants.LF) { return true; } undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 2); return false; } if (nextByte == HttpConstants.LF) { return true; } undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1); return false; } /** * Split one header in Multipart * @return an array of String where rank 0 is the name of the header, follows by several * values that were separated by ';' or ',' */ private static String[] splitMultipartHeader(String sb) { ArrayList headers = new ArrayList(1); int nameStart; int nameEnd; int colonEnd; int valueStart; int valueEnd; nameStart = HttpPostBodyUtil.findNonWhitespace(sb, 0); for (nameEnd = nameStart; nameEnd < sb.length(); nameEnd ++) { char ch = sb.charAt(nameEnd); if (ch == ':' || Character.isWhitespace(ch)) { break; } } for (colonEnd = nameEnd; colonEnd < sb.length(); colonEnd ++) { if (sb.charAt(colonEnd) == ':') { colonEnd ++; break; } } valueStart = HttpPostBodyUtil.findNonWhitespace(sb, colonEnd); valueEnd = HttpPostBodyUtil.findEndOfString(sb); headers.add(sb.substring(nameStart, nameEnd)); String svalue = sb.substring(valueStart, valueEnd); String[] values; if (svalue.indexOf(';') >= 0) { values = StringUtil.split(svalue, ';'); } else { values = StringUtil.split(svalue, ','); } for (String value: values) { headers.add(value.trim()); } String[] array = new String[headers.size()]; for (int i = 0; i < headers.size(); i ++) { array[i] = headers.get(i); } return array; } } HttpPostRequestDecoder.java000066400000000000000000000347671225554127700355220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpConstants; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.util.internal.StringUtil; import java.nio.charset.Charset; import java.util.List; /** * This decoder will decode Body and can handle POST BODY (both multipart and standard). */ @SuppressWarnings("deprecation") public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder { /** * Does this request is a Multipart request */ private final InterfaceHttpPostRequestDecoder decoder; /** * * @param request the request to decode * @throws NullPointerException for request * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostRequestDecoder(HttpRequest request) throws ErrorDataDecoderException, IncompatibleDataDecoderException { this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to decode * @throws NullPointerException for request or factory * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request) throws ErrorDataDecoderException, IncompatibleDataDecoderException { this(factory, request, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to decode * @param charset the charset to use as default * @throws NullPointerException for request or charset or factory * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) throws ErrorDataDecoderException, IncompatibleDataDecoderException { if (factory == null) { throw new NullPointerException("factory"); } if (request == null) { throw new NullPointerException("request"); } if (charset == null) { throw new NullPointerException("charset"); } // Fill default values if (isMultipart(request)) { decoder = new HttpPostMultipartRequestDecoder(factory, request, charset); } else { decoder = new HttpPostStandardRequestDecoder(factory, request, charset); } } /** * states follow * NOTSTARTED PREAMBLE ( * (HEADERDELIMITER DISPOSITION (FIELD | FILEUPLOAD))* * (HEADERDELIMITER DISPOSITION MIXEDPREAMBLE * (MIXEDDELIMITER MIXEDDISPOSITION MIXEDFILEUPLOAD)+ * MIXEDCLOSEDELIMITER)* * CLOSEDELIMITER)+ EPILOGUE * * First status is: NOSTARTED Content-type: multipart/form-data, boundary=AaB03x => PREAMBLE in Header --AaB03x => HEADERDELIMITER content-disposition: form-data; name="field1" => DISPOSITION Joe Blow => FIELD --AaB03x => HEADERDELIMITER content-disposition: form-data; name="pics" => DISPOSITION Content-type: multipart/mixed, boundary=BbC04y --BbC04y => MIXEDDELIMITER Content-disposition: attachment; filename="file1.txt" => MIXEDDISPOSITION Content-Type: text/plain ... contents of file1.txt ... => MIXEDFILEUPLOAD --BbC04y => MIXEDDELIMITER Content-disposition: file; filename="file2.gif" => MIXEDDISPOSITION Content-type: image/gif Content-Transfer-Encoding: binary ...contents of file2.gif... => MIXEDFILEUPLOAD --BbC04y-- => MIXEDCLOSEDELIMITER --AaB03x-- => CLOSEDELIMITER Once CLOSEDELIMITER is found, last status is EPILOGUE */ protected enum MultiPartStatus { NOTSTARTED, PREAMBLE, HEADERDELIMITER, DISPOSITION, FIELD, FILEUPLOAD, MIXEDPREAMBLE, MIXEDDELIMITER, MIXEDDISPOSITION, MIXEDFILEUPLOAD, MIXEDCLOSEDELIMITER, CLOSEDELIMITER, PREEPILOGUE, EPILOGUE } /** * Check if the given request is a multipart request * * @return True if the request is a Multipart request */ public static boolean isMultipart(HttpRequest request) throws ErrorDataDecoderException { if (request.headers().contains(HttpHeaders.Names.CONTENT_TYPE)) { return getMultipartDataBoundary(request.headers().get(HttpHeaders.Names.CONTENT_TYPE)) != null; } else { return false; } } /** * Check from the request ContentType if this request is a Multipart request. * @return an array of String if multipartDataBoundary exists with the multipartDataBoundary * as first element, charset if any as second (missing if not set), else null */ protected static String[] getMultipartDataBoundary(String contentType) throws ErrorDataDecoderException { // Check if Post using "multipart/form-data; boundary=--89421926422648 [; charset=xxx]" String[] headerContentType = splitHeaderContentType(contentType); if (headerContentType[0].toLowerCase().startsWith( HttpHeaders.Values.MULTIPART_FORM_DATA)) { int mrank = 1, crank = 2; if (headerContentType[1].toLowerCase().startsWith( HttpHeaders.Values.BOUNDARY.toString())) { mrank = 1; crank = 2; } else if (headerContentType[2].toLowerCase().startsWith( HttpHeaders.Values.BOUNDARY.toString())) { mrank = 2; crank = 1; } else { return null; } String[] boundary = StringUtil.split(headerContentType[mrank], '='); if (boundary.length != 2) { throw new ErrorDataDecoderException("Needs a boundary value"); } if (headerContentType[crank].toLowerCase().startsWith( HttpHeaders.Values.CHARSET.toString())) { String[] charset = StringUtil.split(headerContentType[crank], '='); if (charset.length > 1) { return new String[] {"--" + boundary[1], charset[1]}; } } return new String[] {"--" + boundary[1]}; } return null; } /** * True if this request is a Multipart request * @return True if this request is a Multipart request */ public boolean isMultipart() { return decoder.isMultipart(); } /** * This method returns a List of all HttpDatas from body.
* * If chunked, all chunks must have been offered using offer() method. * If not, NotEnoughDataDecoderException will be raised. * * @return the list of HttpDatas from Body part for POST method * @throws NotEnoughDataDecoderException Need more chunks */ public List getBodyHttpDatas() throws NotEnoughDataDecoderException { return decoder.getBodyHttpDatas(); } /** * This method returns a List of all HttpDatas with the given name from body.
* * If chunked, all chunks must have been offered using offer() method. * If not, NotEnoughDataDecoderException will be raised. * @return All Body HttpDatas with the given name (ignore case) * @throws NotEnoughDataDecoderException need more chunks */ public List getBodyHttpDatas(String name) throws NotEnoughDataDecoderException { return decoder.getBodyHttpDatas(name); } /** * This method returns the first InterfaceHttpData with the given name from body.
* * If chunked, all chunks must have been offered using offer() method. * If not, NotEnoughDataDecoderException will be raised. * * @return The first Body InterfaceHttpData with the given name (ignore case) * @throws NotEnoughDataDecoderException need more chunks */ public InterfaceHttpData getBodyHttpData(String name) throws NotEnoughDataDecoderException { return decoder.getBodyHttpData(name); } /** * Initialized the internals from a new chunk * @param chunk the new received chunk * @throws ErrorDataDecoderException if there is a problem with the charset decoding or * other errors */ public void offer(HttpChunk chunk) throws ErrorDataDecoderException { decoder.offer(chunk); } /** * True if at current status, there is an available decoded InterfaceHttpData from the Body. * * This method works for chunked and not chunked request. * * @return True if at current status, there is a decoded InterfaceHttpData * @throws EndOfDataDecoderException No more data will be available */ public boolean hasNext() throws EndOfDataDecoderException { return decoder.hasNext(); } /** * Returns the next available InterfaceHttpData or null if, at the time it is called, there is no more * available InterfaceHttpData. A subsequent call to offer(httpChunk) could enable more data. * * @return the next available InterfaceHttpData or null if none * @throws EndOfDataDecoderException No more data will be available */ public InterfaceHttpData next() throws EndOfDataDecoderException { return decoder.next(); } /** * Clean all HttpDatas (on Disk) for the current request. */ public void cleanFiles() { decoder.cleanFiles(); } /** * Remove the given FileUpload from the list of FileUploads to clean */ public void removeHttpDataFromClean(InterfaceHttpData data) { decoder.removeHttpDataFromClean(data); } /** * Split the very first line (Content-Type value) in 3 Strings * @return the array of 3 Strings */ private static String[] splitHeaderContentType(String sb) { int aStart; int aEnd; int bStart; int bEnd; int cStart; int cEnd; aStart = HttpPostBodyUtil.findNonWhitespace(sb, 0); aEnd = sb.indexOf(';'); if (aEnd == -1) { return new String[] { sb, "", "" }; } bStart = HttpPostBodyUtil.findNonWhitespace(sb, aEnd + 1); if (sb.charAt(aEnd - 1) == ' ') { aEnd--; } bEnd = sb.indexOf(';', bStart); if (bEnd == -1) { bEnd = HttpPostBodyUtil.findEndOfString(sb); return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), "" }; } cStart = HttpPostBodyUtil.findNonWhitespace(sb, bEnd + 1); if (sb.charAt(bEnd - 1) == ' ') { bEnd--; } cEnd = HttpPostBodyUtil.findEndOfString(sb); return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), sb.substring(cStart, cEnd) }; } /** * Exception when try reading data from request in chunked format, and not enough * data are available (need more chunks) */ public static class NotEnoughDataDecoderException extends Exception { private static final long serialVersionUID = -7846841864603865638L; public NotEnoughDataDecoderException() { } public NotEnoughDataDecoderException(String msg) { super(msg); } public NotEnoughDataDecoderException(Throwable cause) { super(cause); } public NotEnoughDataDecoderException(String msg, Throwable cause) { super(msg, cause); } } /** * Exception when the body is fully decoded, even if there is still data */ public static class EndOfDataDecoderException extends Exception { private static final long serialVersionUID = 1336267941020800769L; } /** * Exception when an error occurs while decoding */ public static class ErrorDataDecoderException extends Exception { private static final long serialVersionUID = 5020247425493164465L; public ErrorDataDecoderException() { } public ErrorDataDecoderException(String msg) { super(msg); } public ErrorDataDecoderException(Throwable cause) { super(cause); } public ErrorDataDecoderException(String msg, Throwable cause) { super(msg, cause); } } /** * Exception when an unappropriated method was called on a request */ @Deprecated public static class IncompatibleDataDecoderException extends Exception { private static final long serialVersionUID = -953268047926250267L; public IncompatibleDataDecoderException() { } public IncompatibleDataDecoderException(String msg) { super(msg); } public IncompatibleDataDecoderException(Throwable cause) { super(cause); } public IncompatibleDataDecoderException(String msg, Throwable cause) { super(msg, cause); } } } HttpPostRequestEncoder.java000066400000000000000000001171211225554127700355160ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.DefaultHttpChunk; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpConstants; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.stream.ChunkedInput; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Random; import java.util.regex.Pattern; /** * This encoder will help to encode Request for a FORM as POST. */ public class HttpPostRequestEncoder implements ChunkedInput { /** * Different modes to use to encode form data. */ public enum EncoderMode { /** * Legacy mode which should work for most. It is known to not work with OAUTH. For OAUTH use * {@link EncoderMode#RFC3986}. The W3C form recommentations this for submitting post form data. */ RFC1738, /** * Mode which is more new and is used for OAUTH */ RFC3986 } private static final Map percentEncodings = new HashMap(); static { percentEncodings.put(Pattern.compile("\\*"), "%2A"); percentEncodings.put(Pattern.compile("\\+"), "%20"); percentEncodings.put(Pattern.compile("%7E"), "~"); } /** * Factory used to create InterfaceHttpData */ private final HttpDataFactory factory; /** * Request to encode */ private final HttpRequest request; /** * Default charset to use */ private final Charset charset; /** * Chunked false by default */ private boolean isChunked; /** * InterfaceHttpData for Body (without encoding) */ private final List bodyListDatas; /** * The final Multipart List of InterfaceHttpData including encoding */ private final List multipartHttpDatas; /** * Does this request is a Multipart request */ private final boolean isMultipart; /** * If multipart, this is the boundary for the flobal multipart */ private String multipartDataBoundary; /** * If multipart, there could be internal multiparts (mixed) to the global multipart. * Only one level is allowed. */ private String multipartMixedBoundary; /** * To check if the header has been finalized */ private boolean headerFinalized; private final EncoderMode encoderMode; /** * * @param request the request to encode * @param multipart True if the FORM is a ENCTYPE="multipart/form-data" * @throws NullPointerException for request * @throws ErrorDataEncoderException if the request is not a POST */ public HttpPostRequestEncoder(HttpRequest request, boolean multipart) throws ErrorDataEncoderException { this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, multipart, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to encode * @param multipart True if the FORM is a ENCTYPE="multipart/form-data" * @throws NullPointerException for request and factory * @throws ErrorDataEncoderException if the request is not a POST */ public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart) throws ErrorDataEncoderException { this(factory, request, multipart, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to encode * @param multipart True if the FORM is a ENCTYPE="multipart/form-data" * @param charset the charset to use as default * @throws NullPointerException for request or charset or factory * @throws ErrorDataEncoderException if the request is not a POST */ public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart, Charset charset) throws ErrorDataEncoderException { this(factory, request, multipart, charset, EncoderMode.RFC1738); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to encode * @param multipart True if the FORM is a ENCTYPE="multipart/form-data" * @param charset the charset to use as default + @param encoderMode the mode for the encoder to use. See {@link EncoderMode} for the details. * @throws NullPointerException for request or charset or factory * @throws ErrorDataEncoderException if the request is not a POST */ public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart, Charset charset, EncoderMode encoderMode) throws ErrorDataEncoderException { if (factory == null) { throw new NullPointerException("factory"); } if (request == null) { throw new NullPointerException("request"); } if (charset == null) { throw new NullPointerException("charset"); } HttpMethod method = request.getMethod(); if (!(method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH))) { throw new ErrorDataEncoderException("Cannot create a Encoder if not a POST"); } this.request = request; this.charset = charset; this.factory = factory; this.encoderMode = encoderMode; // Fill default values bodyListDatas = new ArrayList(); // default mode isLastChunk = false; isLastChunkSent = false; isMultipart = multipart; multipartHttpDatas = new ArrayList(); if (isMultipart) { initDataMultipart(); } } /** * Clean all HttpDatas (on Disk) for the current request. */ public void cleanFiles() { factory.cleanRequestHttpDatas(request); } /** * Does the last non empty chunk already encoded so that next chunk will be empty (last chunk) */ private boolean isLastChunk; /** * Last chunk already sent */ private boolean isLastChunkSent; /** * The current FileUpload that is currently in encode process */ private FileUpload currentFileUpload; /** * While adding a FileUpload, is the multipart currently in Mixed Mode */ private boolean duringMixedMode; /** * Global Body size */ private long globalBodySize; /** * True if this request is a Multipart request * @return True if this request is a Multipart request */ public boolean isMultipart() { return isMultipart; } /** * Init the delimiter for Global Part (Data). */ private void initDataMultipart() { multipartDataBoundary = getNewMultipartDelimiter(); } /** * Init the delimiter for Mixed Part (Mixed). */ private void initMixedMultipart() { multipartMixedBoundary = getNewMultipartDelimiter(); } /** * * @return a newly generated Delimiter (either for DATA or MIXED) */ private static String getNewMultipartDelimiter() { // construct a generated delimiter Random random = new Random(); return Long.toHexString(random.nextLong()).toLowerCase(); } /** * This method returns a List of all InterfaceHttpData from body part.
* @return the list of InterfaceHttpData from Body part */ public List getBodyListAttributes() { return bodyListDatas; } /** * Set the Body HttpDatas list * @throws NullPointerException for datas * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done */ public void setBodyHttpDatas(List datas) throws ErrorDataEncoderException { if (datas == null) { throw new NullPointerException("datas"); } globalBodySize = 0; bodyListDatas.clear(); currentFileUpload = null; duringMixedMode = false; multipartHttpDatas.clear(); for (InterfaceHttpData data: datas) { addBodyHttpData(data); } } /** * Add a simple attribute in the body as Name=Value * @param name name of the parameter * @param value the value of the parameter * @throws NullPointerException for name * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done */ public void addBodyAttribute(String name, String value) throws ErrorDataEncoderException { if (name == null) { throw new NullPointerException("name"); } String svalue = value; if (value == null) { svalue = ""; } Attribute data = factory.createAttribute(request, name, svalue); addBodyHttpData(data); } /** * Add a file as a FileUpload * @param name the name of the parameter * @param file the file to be uploaded (if not Multipart mode, only the filename will be included) * @param contentType the associated contentType for the File * @param isText True if this file should be transmitted in Text format (else binary) * @throws NullPointerException for name and file * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done */ public void addBodyFileUpload(String name, File file, String contentType, boolean isText) throws ErrorDataEncoderException { if (name == null) { throw new NullPointerException("name"); } if (file == null) { throw new NullPointerException("file"); } String scontentType = contentType; String contentTransferEncoding = null; if (contentType == null) { if (isText) { scontentType = HttpPostBodyUtil.DEFAULT_TEXT_CONTENT_TYPE; } else { scontentType = HttpPostBodyUtil.DEFAULT_BINARY_CONTENT_TYPE; } } if (!isText) { contentTransferEncoding = HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value(); } FileUpload fileUpload = factory.createFileUpload(request, name, file.getName(), scontentType, contentTransferEncoding, null, file.length()); try { fileUpload.setContent(file); } catch (IOException e) { throw new ErrorDataEncoderException(e); } addBodyHttpData(fileUpload); } /** * Add a series of Files associated with one File parameter (implied Mixed mode in Multipart) * @param name the name of the parameter * @param file the array of files * @param contentType the array of content Types associated with each file * @param isText the array of isText attribute (False meaning binary mode) for each file * @throws NullPointerException also throws if array have different sizes * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done */ public void addBodyFileUploads(String name, File[] file, String[] contentType, boolean[] isText) throws ErrorDataEncoderException { if (file.length != contentType.length && file.length != isText.length) { throw new NullPointerException("Different array length"); } for (int i = 0; i < file.length; i++) { addBodyFileUpload(name, file[i], contentType[i], isText[i]); } } /** * Add the InterfaceHttpData to the Body list * @throws NullPointerException for data * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done */ public void addBodyHttpData(InterfaceHttpData data) throws ErrorDataEncoderException { if (headerFinalized) { throw new ErrorDataEncoderException("Cannot add value once finalized"); } if (data == null) { throw new NullPointerException("data"); } bodyListDatas.add(data); if (! isMultipart) { if (data instanceof Attribute) { Attribute attribute = (Attribute) data; try { // name=value& with encoded name and attribute String key = encodeAttribute(attribute.getName(), charset); String value = encodeAttribute(attribute.getValue(), charset); Attribute newattribute = factory.createAttribute(request, key, value); multipartHttpDatas.add(newattribute); globalBodySize += newattribute.getName().length() + 1 + newattribute.length() + 1; } catch (IOException e) { throw new ErrorDataEncoderException(e); } } else if (data instanceof FileUpload) { // since not Multipart, only name=filename => Attribute FileUpload fileUpload = (FileUpload) data; // name=filename& with encoded name and filename String key = encodeAttribute(fileUpload.getName(), charset); String value = encodeAttribute(fileUpload.getFilename(), charset); Attribute newattribute = factory.createAttribute(request, key, value); multipartHttpDatas.add(newattribute); globalBodySize += newattribute.getName().length() + 1 + newattribute.length() + 1; } return; } /* * Logic: * if not Attribute: * add Data to body list * if (duringMixedMode) * add endmixedmultipart delimiter * currentFileUpload = null * duringMixedMode = false; * add multipart delimiter, multipart body header and Data to multipart list * reset currentFileUpload, duringMixedMode * if FileUpload: take care of multiple file for one field => mixed mode * if (duringMixeMode) * if (currentFileUpload.name == data.name) * add mixedmultipart delimiter, mixedmultipart body header and Data to multipart list * else * add endmixedmultipart delimiter, multipart body header and Data to multipart list * currentFileUpload = data * duringMixedMode = false; * else * if (currentFileUpload.name == data.name) * change multipart body header of previous file into multipart list to * mixedmultipart start, mixedmultipart body header * add mixedmultipart delimiter, mixedmultipart body header and Data to multipart list * duringMixedMode = true * else * add multipart delimiter, multipart body header and Data to multipart list * currentFileUpload = data * duringMixedMode = false; * Do not add last delimiter! Could be: * if duringmixedmode: endmixedmultipart + endmultipart * else only endmultipart */ if (data instanceof Attribute) { if (duringMixedMode) { InternalAttribute internal = new InternalAttribute(charset); internal.addValue("\r\n--" + multipartMixedBoundary + "--"); multipartHttpDatas.add(internal); multipartMixedBoundary = null; currentFileUpload = null; duringMixedMode = false; } InternalAttribute internal = new InternalAttribute(charset); if (!multipartHttpDatas.isEmpty()) { // previously a data field so CRLF internal.addValue("\r\n"); } internal.addValue("--" + multipartDataBoundary + "\r\n"); // content-disposition: form-data; name="field1" Attribute attribute = (Attribute) data; internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + attribute.getName() + "\"\r\n"); Charset localcharset = attribute.getCharset(); if (localcharset != null) { // Content-Type: charset=charset internal.addValue(HttpHeaders.Names.CONTENT_TYPE + ": " + HttpPostBodyUtil.DEFAULT_TEXT_CONTENT_TYPE + "; " + HttpHeaders.Values.CHARSET + '=' + localcharset + "\r\n"); } // CRLF between body header and data internal.addValue("\r\n"); multipartHttpDatas.add(internal); multipartHttpDatas.add(data); globalBodySize += attribute.length() + internal.size(); } else if (data instanceof FileUpload) { FileUpload fileUpload = (FileUpload) data; InternalAttribute internal = new InternalAttribute(charset); if (!multipartHttpDatas.isEmpty()) { // previously a data field so CRLF internal.addValue("\r\n"); } boolean localMixed; if (duringMixedMode) { if (currentFileUpload != null && currentFileUpload.getName().equals(fileUpload.getName())) { // continue a mixed mode localMixed = true; } else { // end a mixed mode // add endmixedmultipart delimiter, multipart body header and // Data to multipart list internal.addValue("--" + multipartMixedBoundary + "--"); multipartHttpDatas.add(internal); multipartMixedBoundary = null; // start a new one (could be replaced if mixed start again from here internal = new InternalAttribute(charset); internal.addValue("\r\n"); localMixed = false; // new currentFileUpload and no more in Mixed mode currentFileUpload = fileUpload; duringMixedMode = false; } } else { if (currentFileUpload != null && currentFileUpload.getName().equals(fileUpload.getName())) { // create a new mixed mode (from previous file) // change multipart body header of previous file into multipart list to // mixedmultipart start, mixedmultipart body header // change Internal (size()-2 position in multipartHttpDatas) // from (line starting with *) // --AaB03x // * Content-Disposition: form-data; name="files"; filename="file1.txt" // Content-Type: text/plain // to (lines starting with *) // --AaB03x // * Content-Disposition: form-data; name="files" // * Content-Type: multipart/mixed; boundary=BbC04y // * // * --BbC04y // * Content-Disposition: file; filename="file1.txt" // Content-Type: text/plain initMixedMultipart(); InternalAttribute pastAttribute = (InternalAttribute) multipartHttpDatas.get(multipartHttpDatas.size() - 2); // remove past size globalBodySize -= pastAttribute.size(); String replacement = HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + fileUpload.getName() + "\"\r\n"; replacement += HttpHeaders.Names.CONTENT_TYPE + ": " + HttpPostBodyUtil.MULTIPART_MIXED + "; " + HttpHeaders.Values.BOUNDARY + '=' + multipartMixedBoundary + "\r\n\r\n"; replacement += "--" + multipartMixedBoundary + "\r\n"; replacement += HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FILE + "; " + HttpPostBodyUtil.FILENAME + "=\"" + fileUpload.getFilename() + "\"\r\n"; pastAttribute.setValue(replacement, 1); // update past size globalBodySize += pastAttribute.size(); // now continue // add mixedmultipart delimiter, mixedmultipart body header and // Data to multipart list localMixed = true; duringMixedMode = true; } else { // a simple new multipart //add multipart delimiter, multipart body header and Data to multipart list localMixed = false; currentFileUpload = fileUpload; duringMixedMode = false; } } if (localMixed) { // add mixedmultipart delimiter, mixedmultipart body header and // Data to multipart list internal.addValue("--" + multipartMixedBoundary + "\r\n"); // Content-Disposition: file; filename="file1.txt" internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FILE + "; " + HttpPostBodyUtil.FILENAME + "=\"" + fileUpload.getFilename() + "\"\r\n"); } else { internal.addValue("--" + multipartDataBoundary + "\r\n"); // Content-Disposition: form-data; name="files"; filename="file1.txt" internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + fileUpload.getName() + "\"; " + HttpPostBodyUtil.FILENAME + "=\"" + fileUpload.getFilename() + "\"\r\n"); } // Content-Type: image/gif // Content-Type: text/plain; charset=ISO-8859-1 // Content-Transfer-Encoding: binary internal.addValue(HttpHeaders.Names.CONTENT_TYPE + ": " + fileUpload.getContentType()); String contentTransferEncoding = fileUpload.getContentTransferEncoding(); if (contentTransferEncoding != null && contentTransferEncoding.equals( HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value())) { internal.addValue("\r\n" + HttpHeaders.Names.CONTENT_TRANSFER_ENCODING + ": " + HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value() + "\r\n\r\n"); } else if (fileUpload.getCharset() != null) { internal.addValue("; " + HttpHeaders.Values.CHARSET + '=' + fileUpload.getCharset() + "\r\n\r\n"); } else { internal.addValue("\r\n\r\n"); } multipartHttpDatas.add(internal); multipartHttpDatas.add(data); globalBodySize += fileUpload.length() + internal.size(); } } /** * Iterator to be used when encoding will be called chunk after chunk */ private ListIterator iterator; /** * Finalize the request by preparing the Header in the request and * returns the request ready to be sent.
* Once finalized, no data must be added.
* If the request does not need chunk (isChunked() == false), * this request is the only object to send to * the remote server. * * @return the request object (chunked or not according to size of body) * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done */ public HttpRequest finalizeRequest() throws ErrorDataEncoderException { HttpHeaders headers = request.headers(); // Finalize the multipartHttpDatas if (! headerFinalized) { if (isMultipart) { InternalAttribute internal = new InternalAttribute(charset); if (duringMixedMode) { internal.addValue("\r\n--" + multipartMixedBoundary + "--"); } internal.addValue("\r\n--" + multipartDataBoundary + "--\r\n"); multipartHttpDatas.add(internal); multipartMixedBoundary = null; currentFileUpload = null; duringMixedMode = false; globalBodySize += internal.size(); } headerFinalized = true; } else { throw new ErrorDataEncoderException("Header already encoded"); } List contentTypes = headers.getAll(HttpHeaders.Names.CONTENT_TYPE); List transferEncoding = headers.getAll(HttpHeaders.Names.TRANSFER_ENCODING); if (contentTypes != null) { headers.remove(HttpHeaders.Names.CONTENT_TYPE); for (String contentType: contentTypes) { // "multipart/form-data; boundary=--89421926422648" if (contentType.toLowerCase().startsWith( HttpHeaders.Values.MULTIPART_FORM_DATA)) { // ignore } else if (contentType.toLowerCase().startsWith( HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) { // ignore } else { headers.add(HttpHeaders.Names.CONTENT_TYPE, contentType); } } } if (isMultipart) { String value = HttpHeaders.Values.MULTIPART_FORM_DATA + "; " + HttpHeaders.Values.BOUNDARY + '=' + multipartDataBoundary; headers.add(HttpHeaders.Names.CONTENT_TYPE, value); } else { // Not multipart headers.add(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); } // Now consider size for chunk or not long realSize = globalBodySize; if (isMultipart) { iterator = multipartHttpDatas.listIterator(); } else { realSize -= 1; // last '&' removed iterator = multipartHttpDatas.listIterator(); } headers.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(realSize)); if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) { isChunked = true; if (transferEncoding != null) { headers.remove(HttpHeaders.Names.TRANSFER_ENCODING); for (String v: transferEncoding) { if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) { // ignore } else { headers.add(HttpHeaders.Names.TRANSFER_ENCODING, v); } } } headers.add(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); request.setContent(ChannelBuffers.EMPTY_BUFFER); } else { // get the only one body and set it to the request HttpChunk chunk = nextChunk(); request.setContent(chunk.getContent()); } return request; } /** * @return True if the request is by Chunk */ public boolean isChunked() { return isChunked; } /** * Encode one attribute * @return the encoded attribute * @throws ErrorDataEncoderException if the encoding is in error */ private String encodeAttribute(String s, Charset charset) throws ErrorDataEncoderException { if (s == null) { return ""; } try { String encoded = URLEncoder.encode(s, charset.name()); if (encoderMode == EncoderMode.RFC3986) { for (Map.Entry entry : percentEncodings.entrySet()) { String replacement = entry.getValue(); encoded = entry.getKey().matcher(encoded).replaceAll(replacement); } } return encoded; } catch (UnsupportedEncodingException e) { throw new ErrorDataEncoderException(charset.name(), e); } } /** * The ChannelBuffer currently used by the encoder */ private ChannelBuffer currentBuffer; /** * The current InterfaceHttpData to encode (used if more chunks are available) */ private InterfaceHttpData currentData; /** * If not multipart, does the currentBuffer stands for the Key or for the Value */ private boolean isKey = true; /** * * @return the next ChannelBuffer to send as a HttpChunk and modifying currentBuffer * accordingly */ private ChannelBuffer fillChannelBuffer() { int length = currentBuffer.readableBytes(); if (length > HttpPostBodyUtil.chunkSize) { ChannelBuffer slice = currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize); currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize); return slice; } else { // to continue ChannelBuffer slice = currentBuffer; currentBuffer = null; return slice; } } /** * From the current context (currentBuffer and currentData), returns the next HttpChunk * (if possible) trying to get sizeleft bytes more into the currentBuffer. * This is the Multipart version. * * @param sizeleft the number of bytes to try to get from currentData * @return the next HttpChunk or null if not enough bytes were found * @throws ErrorDataEncoderException if the encoding is in error */ private HttpChunk encodeNextChunkMultipart(int sizeleft) throws ErrorDataEncoderException { if (currentData == null) { return null; } ChannelBuffer buffer; if (currentData instanceof InternalAttribute) { buffer = ((InternalAttribute) currentData).toChannelBuffer(); currentData = null; } else { if (currentData instanceof Attribute) { try { buffer = ((Attribute) currentData).getChunk(sizeleft); } catch (IOException e) { throw new ErrorDataEncoderException(e); } } else { try { buffer = ((HttpData) currentData).getChunk(sizeleft); } catch (IOException e) { throw new ErrorDataEncoderException(e); } } if (buffer.capacity() == 0) { // end for current InterfaceHttpData, need more data currentData = null; return null; } } if (currentBuffer == null) { currentBuffer = buffer; } else { currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer, buffer); } if (currentBuffer.readableBytes() < HttpPostBodyUtil.chunkSize) { currentData = null; return null; } buffer = fillChannelBuffer(); return new DefaultHttpChunk(buffer); } /** * From the current context (currentBuffer and currentData), returns the next HttpChunk * (if possible) trying to get sizeleft bytes more into the currentBuffer. * This is the UrlEncoded version. * * @param sizeleft the number of bytes to try to get from currentData * @return the next HttpChunk or null if not enough bytes were found * @throws ErrorDataEncoderException if the encoding is in error */ private HttpChunk encodeNextChunkUrlEncoded(int sizeleft) throws ErrorDataEncoderException { if (currentData == null) { return null; } int size = sizeleft; ChannelBuffer buffer; if (isKey) { // get name String key = currentData.getName(); buffer = ChannelBuffers.wrappedBuffer(key.getBytes()); isKey = false; if (currentBuffer == null) { currentBuffer = ChannelBuffers.wrappedBuffer( buffer, ChannelBuffers.wrappedBuffer("=".getBytes())); //continue size -= buffer.readableBytes() + 1; } else { currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer, buffer, ChannelBuffers.wrappedBuffer("=".getBytes())); //continue size -= buffer.readableBytes() + 1; } if (currentBuffer.readableBytes() >= HttpPostBodyUtil.chunkSize) { buffer = fillChannelBuffer(); return new DefaultHttpChunk(buffer); } } try { buffer = ((HttpData) currentData).getChunk(size); } catch (IOException e) { throw new ErrorDataEncoderException(e); } ChannelBuffer delimiter = null; if (buffer.readableBytes() < size) { // delimiter isKey = true; delimiter = iterator.hasNext() ? ChannelBuffers.wrappedBuffer("&".getBytes()) : null; } if (buffer.capacity() == 0) { // end for current InterfaceHttpData, need potentially more data currentData = null; if (currentBuffer == null) { currentBuffer = delimiter; } else { if (delimiter != null) { currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer, delimiter); } } if (currentBuffer.readableBytes() >= HttpPostBodyUtil.chunkSize) { buffer = fillChannelBuffer(); return new DefaultHttpChunk(buffer); } return null; } if (currentBuffer == null) { if (delimiter != null) { currentBuffer = ChannelBuffers.wrappedBuffer(buffer, delimiter); } else { currentBuffer = buffer; } } else { if (delimiter != null) { currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer, buffer, delimiter); } else { currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer, buffer); } } if (currentBuffer.readableBytes() < HttpPostBodyUtil.chunkSize) { // end for current InterfaceHttpData, need more data currentData = null; isKey = true; return null; } buffer = fillChannelBuffer(); // size = 0 return new DefaultHttpChunk(buffer); } public void close() throws Exception { //NO since the user can want to reuse (broadcast for instance) cleanFiles(); } /** * Returns the next available HttpChunk. The caller is responsible to test if this chunk is the * last one (isLast()), in order to stop calling this method. * * @return the next available HttpChunk * @throws ErrorDataEncoderException if the encoding is in error */ public HttpChunk nextChunk() throws ErrorDataEncoderException { if (isLastChunk) { isLastChunkSent = true; return new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER); } ChannelBuffer buffer; int size = HttpPostBodyUtil.chunkSize; // first test if previous buffer is not empty if (currentBuffer != null) { size -= currentBuffer.readableBytes(); } if (size <= 0) { //NextChunk from buffer buffer = fillChannelBuffer(); return new DefaultHttpChunk(buffer); } // size > 0 if (currentData != null) { // continue to read data if (isMultipart) { HttpChunk chunk = encodeNextChunkMultipart(size); if (chunk != null) { return chunk; } } else { HttpChunk chunk = encodeNextChunkUrlEncoded(size); if (chunk != null) { //NextChunk Url from currentData return chunk; } } size = HttpPostBodyUtil.chunkSize - currentBuffer.readableBytes(); } if (! iterator.hasNext()) { isLastChunk = true; //NextChunk as last non empty from buffer buffer = currentBuffer; currentBuffer = null; return new DefaultHttpChunk(buffer); } while (size > 0 && iterator.hasNext()) { currentData = iterator.next(); HttpChunk chunk; if (isMultipart) { chunk = encodeNextChunkMultipart(size); } else { chunk = encodeNextChunkUrlEncoded(size); } if (chunk == null) { // not enough size = HttpPostBodyUtil.chunkSize - currentBuffer.readableBytes(); continue; } //NextChunk from data return chunk; } // end since no more data isLastChunk = true; if (currentBuffer == null) { isLastChunkSent = true; //LastChunk with no more data return new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER); } //Previous LastChunk with no more data buffer = currentBuffer; currentBuffer = null; return new DefaultHttpChunk(buffer); } public boolean isEndOfInput() throws Exception { return isLastChunkSent; } public boolean hasNextChunk() throws Exception { return !isLastChunkSent; } /** * Exception when an error occurs while encoding */ public static class ErrorDataEncoderException extends Exception { private static final long serialVersionUID = 5020247425493164465L; public ErrorDataEncoderException() { } public ErrorDataEncoderException(String msg) { super(msg); } public ErrorDataEncoderException(Throwable cause) { super(cause); } public ErrorDataEncoderException(String msg, Throwable cause) { super(msg, cause); } } } HttpPostStandardRequestDecoder.java000066400000000000000000000525161225554127700371730ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpConstants; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException; import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.IncompatibleDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.MultiPartStatus; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException; import org.jboss.netty.util.internal.CaseIgnoringComparator; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * This decoder will decode Body and can handle standard (non multipart) POST BODY. */ @SuppressWarnings({ "deprecation", "RedundantThrowsDeclaration" }) public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestDecoder { /** * Factory used to create InterfaceHttpData */ private final HttpDataFactory factory; /** * Request to decode */ private final HttpRequest request; /** * Default charset to use */ private final Charset charset; /** * Does the last chunk already received */ private boolean isLastChunk; /** * HttpDatas from Body */ private final List bodyListHttpData = new ArrayList(); /** * HttpDatas as Map from Body */ private final Map> bodyMapHttpData = new TreeMap>( CaseIgnoringComparator.INSTANCE); /** * The current channelBuffer */ private ChannelBuffer undecodedChunk; /** * Body HttpDatas current position */ private int bodyListHttpDataRank; /** * Current status */ private MultiPartStatus currentStatus = MultiPartStatus.NOTSTARTED; /** * The current Attribute that is currently in decode process */ private Attribute currentAttribute; /** * * @param request the request to decode * @throws NullPointerException for request * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostStandardRequestDecoder(HttpRequest request) throws ErrorDataDecoderException, IncompatibleDataDecoderException { this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to decode * @throws NullPointerException for request or factory * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostStandardRequestDecoder(HttpDataFactory factory, HttpRequest request) throws ErrorDataDecoderException, IncompatibleDataDecoderException { this(factory, request, HttpConstants.DEFAULT_CHARSET); } /** * * @param factory the factory used to create InterfaceHttpData * @param request the request to decode * @param charset the charset to use as default * @throws NullPointerException for request or charset or factory * @throws IncompatibleDataDecoderException if the request has no body to decode * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors */ public HttpPostStandardRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset) throws ErrorDataDecoderException, IncompatibleDataDecoderException { if (factory == null) { throw new NullPointerException("factory"); } if (request == null) { throw new NullPointerException("request"); } if (charset == null) { throw new NullPointerException("charset"); } this.request = request; this.charset = charset; this.factory = factory; if (!this.request.isChunked()) { undecodedChunk = this.request.getContent(); isLastChunk = true; parseBody(); } } public boolean isMultipart() { return false; } public List getBodyHttpDatas() throws NotEnoughDataDecoderException { if (!isLastChunk) { throw new NotEnoughDataDecoderException(); } return bodyListHttpData; } public List getBodyHttpDatas(String name) throws NotEnoughDataDecoderException { if (!isLastChunk) { throw new NotEnoughDataDecoderException(); } return bodyMapHttpData.get(name); } public InterfaceHttpData getBodyHttpData(String name) throws NotEnoughDataDecoderException { if (!isLastChunk) { throw new NotEnoughDataDecoderException(); } List list = bodyMapHttpData.get(name); if (list != null) { return list.get(0); } return null; } public void offer(HttpChunk chunk) throws ErrorDataDecoderException { ChannelBuffer chunked = chunk.getContent(); if (undecodedChunk == null) { undecodedChunk = chunked; } else { //undecodedChunk = ChannelBuffers.wrappedBuffer(undecodedChunk, chunk.getContent()); // less memory usage undecodedChunk = ChannelBuffers.wrappedBuffer( undecodedChunk, chunked); } if (chunk.isLast()) { isLastChunk = true; } parseBody(); } public boolean hasNext() throws EndOfDataDecoderException { if (currentStatus == MultiPartStatus.EPILOGUE) { // OK except if end of list if (bodyListHttpDataRank >= bodyListHttpData.size()) { throw new EndOfDataDecoderException(); } } return !bodyListHttpData.isEmpty() && bodyListHttpDataRank < bodyListHttpData.size(); } public InterfaceHttpData next() throws EndOfDataDecoderException { if (hasNext()) { return bodyListHttpData.get(bodyListHttpDataRank++); } return null; } /** * This method will parse as much as possible data and fill the list and map * @throws ErrorDataDecoderException if there is a problem with the charset decoding or * other errors */ private void parseBody() throws ErrorDataDecoderException { if (currentStatus == MultiPartStatus.PREEPILOGUE || currentStatus == MultiPartStatus.EPILOGUE) { if (isLastChunk) { currentStatus = MultiPartStatus.EPILOGUE; } return; } parseBodyAttributes(); } /** * Utility function to add a new decoded data */ private void addHttpData(InterfaceHttpData data) { if (data == null) { return; } List datas = bodyMapHttpData.get(data.getName()); if (datas == null) { datas = new ArrayList(1); bodyMapHttpData.put(data.getName(), datas); } datas.add(data); bodyListHttpData.add(data); } /** * This method fill the map and list with as much Attribute as possible from Body in * not Multipart mode. * * @throws ErrorDataDecoderException if there is a problem with the charset decoding or * other errors */ private void parseBodyAttributesStandard() throws ErrorDataDecoderException { int firstpos = undecodedChunk.readerIndex(); int currentpos = firstpos; int equalpos; int ampersandpos; if (currentStatus == MultiPartStatus.NOTSTARTED) { currentStatus = MultiPartStatus.DISPOSITION; } boolean contRead = true; try { while (undecodedChunk.readable() && contRead) { char read = (char) undecodedChunk.readUnsignedByte(); currentpos++; switch (currentStatus) { case DISPOSITION:// search '=' if (read == '=') { currentStatus = MultiPartStatus.FIELD; equalpos = currentpos - 1; String key = decodeAttribute( undecodedChunk.toString(firstpos, equalpos - firstpos, charset), charset); currentAttribute = factory.createAttribute(request, key); firstpos = currentpos; } else if (read == '&') { // special empty FIELD currentStatus = MultiPartStatus.DISPOSITION; ampersandpos = currentpos - 1; String key = decodeAttribute( undecodedChunk.toString(firstpos, ampersandpos - firstpos, charset), charset); currentAttribute = factory.createAttribute(request, key); currentAttribute.setValue(""); // empty addHttpData(currentAttribute); currentAttribute = null; firstpos = currentpos; contRead = true; } break; case FIELD:// search '&' or end of line if (read == '&') { currentStatus = MultiPartStatus.DISPOSITION; ampersandpos = currentpos - 1; setFinalBuffer(undecodedChunk.slice(firstpos, ampersandpos - firstpos)); firstpos = currentpos; contRead = true; } else if (read == HttpConstants.CR) { if (undecodedChunk.readable()) { read = (char) undecodedChunk.readUnsignedByte(); currentpos++; if (read == HttpConstants.LF) { currentStatus = MultiPartStatus.PREEPILOGUE; ampersandpos = currentpos - 2; setFinalBuffer( undecodedChunk.slice(firstpos, ampersandpos - firstpos)); firstpos = currentpos; contRead = false; } else { // Error throw new ErrorDataDecoderException("Bad end of line"); } } else { currentpos--; } } else if (read == HttpConstants.LF) { currentStatus = MultiPartStatus.PREEPILOGUE; ampersandpos = currentpos - 1; setFinalBuffer( undecodedChunk.slice(firstpos, ampersandpos - firstpos)); firstpos = currentpos; contRead = false; } break; default: // just stop contRead = false; } } if (isLastChunk && currentAttribute != null) { // special case ampersandpos = currentpos; if (ampersandpos > firstpos) { setFinalBuffer( undecodedChunk.slice(firstpos, ampersandpos - firstpos)); } else if (! currentAttribute.isCompleted()) { setFinalBuffer(ChannelBuffers.EMPTY_BUFFER); } firstpos = currentpos; currentStatus = MultiPartStatus.EPILOGUE; return; } if (contRead && currentAttribute != null) { // reset index except if to continue in case of FIELD status if (currentStatus == MultiPartStatus.FIELD) { currentAttribute.addContent( undecodedChunk.slice(firstpos, currentpos - firstpos), false); firstpos = currentpos; } undecodedChunk.readerIndex(firstpos); } else { // end of line so keep index } } catch (ErrorDataDecoderException e) { // error while decoding undecodedChunk.readerIndex(firstpos); throw e; } catch (IOException e) { // error while decoding undecodedChunk.readerIndex(firstpos); throw new ErrorDataDecoderException(e); } } /** * This method fill the map and list with as much Attribute as possible from Body in * not Multipart mode. * * @throws ErrorDataDecoderException if there is a problem with the charset decoding or * other errors */ private void parseBodyAttributes() throws ErrorDataDecoderException { SeekAheadOptimize sao; try { sao = new SeekAheadOptimize(undecodedChunk); } catch (SeekAheadNoBackArrayException e1) { parseBodyAttributesStandard(); return; } int firstpos = undecodedChunk.readerIndex(); int currentpos = firstpos; int equalpos; int ampersandpos; if (currentStatus == MultiPartStatus.NOTSTARTED) { currentStatus = MultiPartStatus.DISPOSITION; } boolean contRead = true; try { loop: while (sao.pos < sao.limit) { char read = (char) (sao.bytes[sao.pos ++] & 0xFF); currentpos ++; switch (currentStatus) { case DISPOSITION:// search '=' if (read == '=') { currentStatus = MultiPartStatus.FIELD; equalpos = currentpos - 1; String key = decodeAttribute( undecodedChunk.toString(firstpos, equalpos - firstpos, charset), charset); currentAttribute = factory.createAttribute(request, key); firstpos = currentpos; } else if (read == '&') { // special empty FIELD currentStatus = MultiPartStatus.DISPOSITION; ampersandpos = currentpos - 1; String key = decodeAttribute( undecodedChunk.toString(firstpos, ampersandpos - firstpos, charset), charset); currentAttribute = factory.createAttribute(request, key); currentAttribute.setValue(""); // empty addHttpData(currentAttribute); currentAttribute = null; firstpos = currentpos; contRead = true; } break; case FIELD:// search '&' or end of line if (read == '&') { currentStatus = MultiPartStatus.DISPOSITION; ampersandpos = currentpos - 1; setFinalBuffer(undecodedChunk.slice(firstpos, ampersandpos - firstpos)); firstpos = currentpos; contRead = true; } else if (read == HttpConstants.CR) { if (sao.pos < sao.limit) { read = (char) (sao.bytes[sao.pos ++] & 0xFF); currentpos++; if (read == HttpConstants.LF) { currentStatus = MultiPartStatus.PREEPILOGUE; ampersandpos = currentpos - 2; sao.setReadPosition(0); setFinalBuffer( undecodedChunk.slice(firstpos, ampersandpos - firstpos)); firstpos = currentpos; contRead = false; break loop; } else { // Error sao.setReadPosition(0); throw new ErrorDataDecoderException("Bad end of line"); } } else { if (sao.limit > 0) { currentpos --; } } } else if (read == HttpConstants.LF) { currentStatus = MultiPartStatus.PREEPILOGUE; ampersandpos = currentpos - 1; sao.setReadPosition(0); setFinalBuffer( undecodedChunk.slice(firstpos, ampersandpos - firstpos)); firstpos = currentpos; contRead = false; break loop; } break; default: // just stop sao.setReadPosition(0); contRead = false; break loop; } } if (isLastChunk && currentAttribute != null) { // special case ampersandpos = currentpos; if (ampersandpos > firstpos) { setFinalBuffer( undecodedChunk.slice(firstpos, ampersandpos - firstpos)); } else if (! currentAttribute.isCompleted()) { setFinalBuffer(ChannelBuffers.EMPTY_BUFFER); } firstpos = currentpos; currentStatus = MultiPartStatus.EPILOGUE; return; } if (contRead && currentAttribute != null) { // reset index except if to continue in case of FIELD status if (currentStatus == MultiPartStatus.FIELD) { currentAttribute.addContent( undecodedChunk.slice(firstpos, currentpos - firstpos), false); firstpos = currentpos; } undecodedChunk.readerIndex(firstpos); } else { // end of line so keep index } } catch (ErrorDataDecoderException e) { // error while decoding undecodedChunk.readerIndex(firstpos); throw e; } catch (IOException e) { // error while decoding undecodedChunk.readerIndex(firstpos); throw new ErrorDataDecoderException(e); } } private void setFinalBuffer(ChannelBuffer buffer) throws ErrorDataDecoderException, IOException { currentAttribute.addContent(buffer, true); String value = decodeAttribute( currentAttribute.getChannelBuffer().toString(charset), charset); currentAttribute.setValue(value); addHttpData(currentAttribute); currentAttribute = null; } /** * Decode component * @return the decoded component */ private static String decodeAttribute(String s, Charset charset) throws ErrorDataDecoderException { if (s == null) { return ""; } try { return URLDecoder.decode(s, charset.name()); } catch (UnsupportedEncodingException e) { throw new ErrorDataDecoderException(charset.toString(), e); } catch (IllegalArgumentException e) { throw new ErrorDataDecoderException("Bad string: '" + s + '\'', e); } } public void cleanFiles() { factory.cleanRequestHttpDatas(request); } public void removeHttpDataFromClean(InterfaceHttpData data) { factory.removeHttpDataFromClean(request, data); } } InterfaceHttpData.java000066400000000000000000000021541225554127700344110ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; /** * Interface for all Objects that could be encoded/decoded using HttpPostRequestEncoder/Decoder */ public interface InterfaceHttpData extends Comparable { enum HttpDataType { Attribute, FileUpload, InternalAttribute } /** * Returns the name of this InterfaceHttpData. */ String getName(); /** * * @return The HttpDataType */ HttpDataType getHttpDataType(); } InterfaceHttpPostRequestDecoder.java000066400000000000000000000100101225554127700373120ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import java.util.List; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException; public interface InterfaceHttpPostRequestDecoder { /** * True if this request is a Multipart request * @return True if this request is a Multipart request */ boolean isMultipart(); /** * This method returns a List of all HttpDatas from body.
* * If chunked, all chunks must have been offered using offer() method. * If not, NotEnoughDataDecoderException will be raised. * * @return the list of HttpDatas from Body part for POST method * @throws NotEnoughDataDecoderException Need more chunks */ List getBodyHttpDatas() throws NotEnoughDataDecoderException; /** * This method returns a List of all HttpDatas with the given name from body.
* * If chunked, all chunks must have been offered using offer() method. * If not, NotEnoughDataDecoderException will be raised. * @return All Body HttpDatas with the given name (ignore case) * @throws NotEnoughDataDecoderException need more chunks */ List getBodyHttpDatas(String name) throws NotEnoughDataDecoderException; /** * This method returns the first InterfaceHttpData with the given name from body.
* * If chunked, all chunks must have been offered using offer() method. * If not, NotEnoughDataDecoderException will be raised. * * @return The first Body InterfaceHttpData with the given name (ignore case) * @throws NotEnoughDataDecoderException need more chunks */ InterfaceHttpData getBodyHttpData(String name) throws NotEnoughDataDecoderException; /** * Initialized the internals from a new chunk * @param chunk the new received chunk * @throws ErrorDataDecoderException if there is a problem with the charset decoding or * other errors */ void offer(HttpChunk chunk) throws ErrorDataDecoderException; /** * True if at current status, there is an available decoded InterfaceHttpData from the Body. * * This method works for chunked and not chunked request. * * @return True if at current status, there is a decoded InterfaceHttpData * @throws EndOfDataDecoderException No more data will be available */ boolean hasNext() throws EndOfDataDecoderException; /** * Returns the next available InterfaceHttpData or null if, at the time it is called, there is no more * available InterfaceHttpData. A subsequent call to offer(httpChunk) could enable more data. * * @return the next available InterfaceHttpData or null if none * @throws EndOfDataDecoderException No more data will be available */ InterfaceHttpData next() throws EndOfDataDecoderException; /** * Clean all HttpDatas (on Disk) for the current request. */ void cleanFiles(); /** * Remove the given FileUpload from the list of FileUploads to clean */ void removeHttpDataFromClean(InterfaceHttpData data); } InternalAttribute.java000066400000000000000000000073341225554127700345240ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.CharsetUtil; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; /** * This Attribute is only for Encoder use to insert special command between object if needed * (like Multipart Mixed mode) */ public class InternalAttribute implements InterfaceHttpData { protected final List value = new ArrayList(); private final Charset charset; @Deprecated public InternalAttribute() { this(CharsetUtil.UTF_8); } public InternalAttribute(Charset charset) { this.charset = charset; } public HttpDataType getHttpDataType() { return HttpDataType.InternalAttribute; } @Deprecated public List getValue() { return value; } public void addValue(String value) { if (value == null) { throw new NullPointerException("value"); } this.value.add(value); } public void addValue(String value, int rank) { if (value == null) { throw new NullPointerException("value"); } this.value.add(rank, value); } public void setValue(String value, int rank) { if (value == null) { throw new NullPointerException("value"); } this.value.set(rank, value); } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof Attribute)) { return false; } Attribute attribute = (Attribute) o; return getName().equalsIgnoreCase(attribute.getName()); } public int compareTo(InterfaceHttpData o) { if (!(o instanceof InternalAttribute)) { throw new ClassCastException("Cannot compare " + getHttpDataType() + " with " + o.getHttpDataType()); } return compareTo((InternalAttribute) o); } public int compareTo(InternalAttribute o) { return getName().compareToIgnoreCase(o.getName()); } public int size() { int size = 0; for (String elt : value) { try { size += elt.getBytes(charset.name()).length; } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } return size; } @Override public String toString() { StringBuilder result = new StringBuilder(); for (String elt : value) { result.append(elt); } return result.toString(); } public ChannelBuffer toChannelBuffer() { ChannelBuffer[] buffers = new ChannelBuffer[value.size()]; for (int i = 0; i < buffers.length; i++) { buffers[i] = ChannelBuffers.copiedBuffer(value.get(i), charset); } return ChannelBuffers.wrappedBuffer(buffers); } public String getName() { return "InternalAttribute"; } } MemoryAttribute.java000066400000000000000000000060311225554127700342110ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.HttpConstants; import java.io.IOException; /** * Memory implementation of Attributes */ public class MemoryAttribute extends AbstractMemoryHttpData implements Attribute { public MemoryAttribute(String name) { super(name, HttpConstants.DEFAULT_CHARSET, 0); } public MemoryAttribute(String name, String value) throws IOException { super(name, HttpConstants.DEFAULT_CHARSET, 0); // Attribute have no default size setValue(value); } public HttpDataType getHttpDataType() { return HttpDataType.Attribute; } public String getValue() { return getChannelBuffer().toString(charset); } public void setValue(String value) throws IOException { if (value == null) { throw new NullPointerException("value"); } byte [] bytes = value.getBytes(charset.name()); checkSize(bytes.length); ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(bytes); if (definedSize > 0) { definedSize = buffer.readableBytes(); } setContent(buffer); } @Override public void addContent(ChannelBuffer buffer, boolean last) throws IOException { int localsize = buffer.readableBytes(); checkSize(size + localsize); if (definedSize > 0 && definedSize < size + localsize) { definedSize = size + localsize; } super.addContent(buffer, last); } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof Attribute)) { return false; } Attribute attribute = (Attribute) o; return getName().equalsIgnoreCase(attribute.getName()); } public int compareTo(InterfaceHttpData other) { if (!(other instanceof Attribute)) { throw new ClassCastException("Cannot compare " + getHttpDataType() + " with " + other.getHttpDataType()); } return compareTo((Attribute) other); } public int compareTo(Attribute o) { return getName().compareToIgnoreCase(o.getName()); } @Override public String toString() { return getName() + '=' + getValue(); } } MemoryFileUpload.java000066400000000000000000000072721225554127700343020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.handler.codec.http.HttpHeaders; import java.nio.charset.Charset; /** * Default FileUpload implementation that stores file into memory.

* * Warning: be aware of the memory limitation. */ public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUpload { private String filename; private String contentType; private String contentTransferEncoding; public MemoryFileUpload(String name, String filename, String contentType, String contentTransferEncoding, Charset charset, long size) { super(name, charset, size); setFilename(filename); setContentType(contentType); setContentTransferEncoding(contentTransferEncoding); } public HttpDataType getHttpDataType() { return HttpDataType.FileUpload; } public String getFilename() { return filename; } public void setFilename(String filename) { if (filename == null) { throw new NullPointerException("filename"); } this.filename = filename; } @Override public int hashCode() { return getName().hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof Attribute)) { return false; } Attribute attribute = (Attribute) o; return getName().equalsIgnoreCase(attribute.getName()); } public int compareTo(InterfaceHttpData o) { if (!(o instanceof FileUpload)) { throw new ClassCastException("Cannot compare " + getHttpDataType() + " with " + o.getHttpDataType()); } return compareTo((FileUpload) o); } public int compareTo(FileUpload o) { int v; v = getName().compareToIgnoreCase(o.getName()); if (v != 0) { return v; } // TODO should we compare size for instance ? return v; } public void setContentType(String contentType) { if (contentType == null) { throw new NullPointerException("contentType"); } this.contentType = contentType; } public String getContentType() { return contentType; } public String getContentTransferEncoding() { return contentTransferEncoding; } public void setContentTransferEncoding(String contentTransferEncoding) { this.contentTransferEncoding = contentTransferEncoding; } @Override public String toString() { return HttpPostBodyUtil.CONTENT_DISPOSITION + ": " + HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + getName() + "\"; " + HttpPostBodyUtil.FILENAME + "=\"" + filename + "\"\r\n" + HttpHeaders.Names.CONTENT_TYPE + ": " + contentType + (charset != null? "; " + HttpHeaders.Values.CHARSET + '=' + charset + "\r\n" : "\r\n") + HttpHeaders.Names.CONTENT_LENGTH + ": " + length() + "\r\n" + "Completed: " + isCompleted() + "\r\nIsInMemory: " + isInMemory(); } } MixedAttribute.java000066400000000000000000000140241225554127700340100ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.jboss.netty.buffer.ChannelBuffer; /** * Mixed implementation using both in Memory and in File with a limit of size */ public class MixedAttribute implements Attribute { private Attribute attribute; private final long limitSize; protected long maxSize = DefaultHttpDataFactory.MAXSIZE; public MixedAttribute(String name, long limitSize) { this.limitSize = limitSize; attribute = new MemoryAttribute(name); } public MixedAttribute(String name, String value, long limitSize) { this.limitSize = limitSize; if (value.length() > this.limitSize) { try { attribute = new DiskAttribute(name, value); } catch (IOException e) { // revert to Memory mode try { attribute = new MemoryAttribute(name, value); } catch (IOException e1) { throw new IllegalArgumentException(e); } } } else { try { attribute = new MemoryAttribute(name, value); } catch (IOException e) { throw new IllegalArgumentException(e); } } } public void setMaxSize(long maxSize) { this.maxSize = maxSize; attribute.setMaxSize(maxSize); } public void checkSize(long newSize) throws IOException { if (maxSize >= 0 && newSize > maxSize) { throw new IOException("Size exceed allowed maximum capacity"); } } public void addContent(ChannelBuffer buffer, boolean last) throws IOException { if (attribute instanceof MemoryAttribute) { checkSize(attribute.length() + buffer.readableBytes()); if (attribute.length() + buffer.readableBytes() > limitSize) { DiskAttribute diskAttribute = new DiskAttribute(attribute .getName()); diskAttribute.setMaxSize(maxSize); if (((MemoryAttribute) attribute).getChannelBuffer() != null) { diskAttribute.addContent(((MemoryAttribute) attribute) .getChannelBuffer(), false); } attribute = diskAttribute; } } attribute.addContent(buffer, last); } public void delete() { attribute.delete(); } public byte[] get() throws IOException { return attribute.get(); } public ChannelBuffer getChannelBuffer() throws IOException { return attribute.getChannelBuffer(); } public Charset getCharset() { return attribute.getCharset(); } public String getString() throws IOException { return attribute.getString(); } public String getString(Charset encoding) throws IOException { return attribute.getString(encoding); } public boolean isCompleted() { return attribute.isCompleted(); } public boolean isInMemory() { return attribute.isInMemory(); } public long length() { return attribute.length(); } public boolean renameTo(File dest) throws IOException { return attribute.renameTo(dest); } public void setCharset(Charset charset) { attribute.setCharset(charset); } public void setContent(ChannelBuffer buffer) throws IOException { checkSize(buffer.readableBytes()); if (buffer.readableBytes() > limitSize) { if (attribute instanceof MemoryAttribute) { // change to Disk attribute = new DiskAttribute(attribute.getName()); attribute.setMaxSize(maxSize); } } attribute.setContent(buffer); } public void setContent(File file) throws IOException { checkSize(file.length()); if (file.length() > limitSize) { if (attribute instanceof MemoryAttribute) { // change to Disk attribute = new DiskAttribute(attribute.getName()); attribute.setMaxSize(maxSize); } } attribute.setContent(file); } public void setContent(InputStream inputStream) throws IOException { if (attribute instanceof MemoryAttribute) { // change to Disk even if we don't know the size attribute = new DiskAttribute(attribute.getName()); attribute.setMaxSize(maxSize); } attribute.setContent(inputStream); } public HttpDataType getHttpDataType() { return attribute.getHttpDataType(); } public String getName() { return attribute.getName(); } public int compareTo(InterfaceHttpData o) { return attribute.compareTo(o); } @Override public String toString() { return "Mixed: " + attribute.toString(); } public String getValue() throws IOException { return attribute.getValue(); } public void setValue(String value) throws IOException { if (value != null) { checkSize(value.getBytes().length); } attribute.setValue(value); } public ChannelBuffer getChunk(int length) throws IOException { return attribute.getChunk(length); } public File getFile() throws IOException { return attribute.getFile(); } } MixedFileUpload.java000066400000000000000000000160071225554127700340740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.jboss.netty.buffer.ChannelBuffer; /** * Mixed implementation using both in Memory and in File with a limit of size */ public class MixedFileUpload implements FileUpload { private FileUpload fileUpload; private final long limitSize; private final long definedSize; protected long maxSize = DefaultHttpDataFactory.MAXSIZE; public MixedFileUpload(String name, String filename, String contentType, String contentTransferEncoding, Charset charset, long size, long limitSize) { this.limitSize = limitSize; if (size > this.limitSize) { fileUpload = new DiskFileUpload(name, filename, contentType, contentTransferEncoding, charset, size); } else { fileUpload = new MemoryFileUpload(name, filename, contentType, contentTransferEncoding, charset, size); } definedSize = size; } public void setMaxSize(long maxSize) { this.maxSize = maxSize; fileUpload.setMaxSize(maxSize); } public void checkSize(long newSize) throws IOException { if (maxSize >= 0 && newSize > maxSize) { throw new IOException("Size exceed allowed maximum capacity"); } } public void addContent(ChannelBuffer buffer, boolean last) throws IOException { if (fileUpload instanceof MemoryFileUpload) { checkSize(fileUpload.length() + buffer.readableBytes()); if (fileUpload.length() + buffer.readableBytes() > limitSize) { DiskFileUpload diskFileUpload = new DiskFileUpload(fileUpload .getName(), fileUpload.getFilename(), fileUpload .getContentType(), fileUpload .getContentTransferEncoding(), fileUpload.getCharset(), definedSize); diskFileUpload.setMaxSize(maxSize); if (((MemoryFileUpload) fileUpload).getChannelBuffer() != null) { diskFileUpload.addContent(((MemoryFileUpload) fileUpload) .getChannelBuffer(), false); } fileUpload = diskFileUpload; } } fileUpload.addContent(buffer, last); } public void delete() { fileUpload.delete(); } public byte[] get() throws IOException { return fileUpload.get(); } public ChannelBuffer getChannelBuffer() throws IOException { return fileUpload.getChannelBuffer(); } public Charset getCharset() { return fileUpload.getCharset(); } public String getContentType() { return fileUpload.getContentType(); } public String getContentTransferEncoding() { return fileUpload.getContentTransferEncoding(); } public String getFilename() { return fileUpload.getFilename(); } public String getString() throws IOException { return fileUpload.getString(); } public String getString(Charset encoding) throws IOException { return fileUpload.getString(encoding); } public boolean isCompleted() { return fileUpload.isCompleted(); } public boolean isInMemory() { return fileUpload.isInMemory(); } public long length() { return fileUpload.length(); } public boolean renameTo(File dest) throws IOException { return fileUpload.renameTo(dest); } public void setCharset(Charset charset) { fileUpload.setCharset(charset); } public void setContent(ChannelBuffer buffer) throws IOException { checkSize(buffer.readableBytes()); if (buffer.readableBytes() > limitSize) { if (fileUpload instanceof MemoryFileUpload) { // change to Disk fileUpload = new DiskFileUpload(fileUpload .getName(), fileUpload.getFilename(), fileUpload .getContentType(), fileUpload .getContentTransferEncoding(), fileUpload.getCharset(), definedSize); fileUpload.setMaxSize(maxSize); } } fileUpload.setContent(buffer); } public void setContent(File file) throws IOException { checkSize(file.length()); if (file.length() > limitSize) { if (fileUpload instanceof MemoryFileUpload) { // change to Disk fileUpload = new DiskFileUpload(fileUpload .getName(), fileUpload.getFilename(), fileUpload .getContentType(), fileUpload .getContentTransferEncoding(), fileUpload.getCharset(), definedSize); fileUpload.setMaxSize(maxSize); } } fileUpload.setContent(file); } public void setContent(InputStream inputStream) throws IOException { if (fileUpload instanceof MemoryFileUpload) { // change to Disk fileUpload = new DiskFileUpload(fileUpload .getName(), fileUpload.getFilename(), fileUpload .getContentType(), fileUpload .getContentTransferEncoding(), fileUpload.getCharset(), definedSize); fileUpload.setMaxSize(maxSize); } fileUpload.setContent(inputStream); } public void setContentType(String contentType) { fileUpload.setContentType(contentType); } public void setContentTransferEncoding(String contentTransferEncoding) { fileUpload.setContentTransferEncoding(contentTransferEncoding); } public void setFilename(String filename) { fileUpload.setFilename(filename); } public HttpDataType getHttpDataType() { return fileUpload.getHttpDataType(); } public String getName() { return fileUpload.getName(); } public int compareTo(InterfaceHttpData o) { return fileUpload.compareTo(o); } @Override public String toString() { return "Mixed: " + fileUpload.toString(); } public ChannelBuffer getChunk(int length) throws IOException { return fileUpload.getChunk(length); } public File getFile() throws IOException { return fileUpload.getFile(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/multipart/package-info.java000066400000000000000000000013251225554127700334610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * HTTP multipart support. */ package org.jboss.netty.handler.codec.http.multipart; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/package-info.java000066400000000000000000000020451225554127700314400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder, decoder and their related message types for HTTP. * * @apiviz.exclude ^java\.lang\. * @apiviz.exclude OneToOne(Encoder|Decoder)$ * @apiviz.exclude \.HttpHeaders\. * @apiviz.exclude \.codec\.replay\. * @apiviz.exclude \.(Simple)?Channel[A-Za-z]*Handler$ * @apiviz.exclude \.Rtsp * @apiviz.exclude \.Default * @apiviz.exclude \.Http(Client|Server)Codec$ */ package org.jboss.netty.handler.codec.http; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocket/000077500000000000000000000000001225554127700302365ustar00rootroot00000000000000DefaultWebSocketFrame.java000066400000000000000000000063131225554127700351730ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocket; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.CharsetUtil; /** * @deprecated Use org.jboss.netty.handler.codec.http.websocketx instead. * * The default {@link WebSocketFrame} implementation. */ @Deprecated public class DefaultWebSocketFrame implements WebSocketFrame { private int type; private ChannelBuffer binaryData; /** * Creates a new empty text frame. */ public DefaultWebSocketFrame() { this(0, ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new text frame from with the specified string. */ public DefaultWebSocketFrame(String textData) { this(0, ChannelBuffers.copiedBuffer(textData, CharsetUtil.UTF_8)); } /** * Creates a new frame with the specified frame type and the specified data. * * @param type * the type of the frame. {@code 0} is the only allowed type currently. * @param binaryData * the content of the frame. If (type & 0x80 == 0), * it must be encoded in UTF-8. * * @throws IllegalArgumentException * if If (type & 0x80 == 0) and the data is not encoded * in UTF-8 */ public DefaultWebSocketFrame(int type, ChannelBuffer binaryData) { setData(type, binaryData); } public int getType() { return type; } public boolean isText() { return (getType() & 0x80) == 0; } public boolean isBinary() { return !isText(); } public ChannelBuffer getBinaryData() { return binaryData; } public String getTextData() { return getBinaryData().toString(CharsetUtil.UTF_8); } public void setData(int type, ChannelBuffer binaryData) { if (binaryData == null) { throw new NullPointerException("binaryData"); } if ((type & 0x80) == 0) { // If text, data should not contain 0xFF. int delimPos = binaryData.indexOf( binaryData.readerIndex(), binaryData.writerIndex(), (byte) 0xFF); if (delimPos >= 0) { throw new IllegalArgumentException( "a text frame should not contain 0xFF."); } } this.type = type & 0xFF; this.binaryData = binaryData; } @Override public String toString() { return getClass().getSimpleName() + "(type: " + getType() + ", " + "data: " + getBinaryData() + ')'; } } WebSocketFrame.java000066400000000000000000000052221225554127700336640ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocket; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * @deprecated Use org.jboss.netty.handler.codec.http.websocketx instead. * * A Web Socket frame that represents either text or binary data. */ @Deprecated public interface WebSocketFrame { /** * Closing handshake message (0xFF, 0x00) */ WebSocketFrame CLOSING_HANDSHAKE = new DefaultWebSocketFrame(0xFF, ChannelBuffers.EMPTY_BUFFER); /** * Returns the type of this frame. * 0x00-0x7F means a text frame encoded in UTF-8, and * 0x80-0xFF means a binary frame. Currently, {@code 0} is the * only allowed type according to the specification. */ int getType(); /** * Returns {@code true} if and only if the content of this frame is a string * encoded in UTF-8. */ boolean isText(); /** * Returns {@code true} if and only if the content of this frame is an * arbitrary binary data. */ boolean isBinary(); /** * Returns the content of this frame as-is, with no UTF-8 decoding. */ ChannelBuffer getBinaryData(); /** * Converts the content of this frame into a UTF-8 string and returns the * converted string. */ String getTextData(); /** * Sets the type and the content of this frame. * * @param type * the type of the frame. {@code 0} is the only allowed type currently. * @param binaryData * the content of the frame. If (type & 0x80 == 0), * it must be encoded in UTF-8. * * @throws IllegalArgumentException * if If (type & 0x80 == 0) and the data is not encoded * in UTF-8 */ void setData(int type, ChannelBuffer binaryData); /** * Returns the string representation of this frame. Please note that this * method is not identical to {@link #getTextData()}. */ String toString(); } WebSocketFrameDecoder.java000066400000000000000000000111031225554127700351450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocket; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.handler.codec.replay.VoidEnum; /** * @deprecated Use org.jboss.netty.handler.codec.http.websocketx instead. * * Decodes {@link ChannelBuffer}s into {@link WebSocketFrame}s. *

* For the detailed instruction on adding add Web Socket support to your HTTP * server, take a look into the WebSocketServer example located in the * {@code org.jboss.netty.example.http.websocket} package. * @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.http.websocket.WebSocketFrame */ @Deprecated public class WebSocketFrameDecoder extends ReplayingDecoder { public static final int DEFAULT_MAX_FRAME_SIZE = 16384; private final int maxFrameSize; private boolean receivedClosingHandshake; public WebSocketFrameDecoder() { this(DEFAULT_MAX_FRAME_SIZE); } /** * Creates a new instance of {@code WebSocketFrameDecoder} with the specified {@code maxFrameSize}. If the client * sends a frame size larger than {@code maxFrameSize}, the channel will be closed. * * @param maxFrameSize the maximum frame size to decode */ public WebSocketFrameDecoder(int maxFrameSize) { this.maxFrameSize = maxFrameSize; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { // Discard all data received if closing handshake was received before. if (receivedClosingHandshake) { buffer.skipBytes(actualReadableBytes()); return null; } // Decode a frame otherwise. byte type = buffer.readByte(); if ((type & 0x80) == 0x80) { // If the MSB on type is set, decode the frame length return decodeBinaryFrame(type, buffer); } else { // Decode a 0xff terminated UTF-8 string return decodeTextFrame(type, buffer); } } private WebSocketFrame decodeBinaryFrame(int type, ChannelBuffer buffer) throws TooLongFrameException { long frameSize = 0; int lengthFieldSize = 0; byte b; do { b = buffer.readByte(); frameSize <<= 7; frameSize |= b & 0x7f; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } lengthFieldSize ++; if (lengthFieldSize > 8) { // Perhaps a malicious peer? throw new TooLongFrameException(); } } while ((b & 0x80) == 0x80); if (type == 0xFF && frameSize == 0) { receivedClosingHandshake = true; } return new DefaultWebSocketFrame( type, buffer.readBytes((int) frameSize)); } private WebSocketFrame decodeTextFrame(int type, ChannelBuffer buffer) throws TooLongFrameException { int ridx = buffer.readerIndex(); int rbytes = actualReadableBytes(); int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF); if (delimPos == -1) { // Frame delimiter (0xFF) not found if (rbytes > maxFrameSize) { // Frame length exceeded the maximum throw new TooLongFrameException(); } else { // Wait until more data is received return null; } } int frameSize = delimPos - ridx; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } ChannelBuffer binaryData = buffer.readBytes(frameSize); buffer.skipBytes(1); return new DefaultWebSocketFrame(type, binaryData); } } WebSocketFrameEncoder.java000066400000000000000000000074451225554127700351750ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocket; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * @deprecated Use org.jboss.netty.handler.codec.http.websocketx instead. * * Encodes a {@link WebSocketFrame} into a {@link ChannelBuffer}. *

* For the detailed instruction on adding add Web Socket support to your HTTP * server, take a look into the WebSocketServer example located in the * {@code org.jboss.netty.example.http.websocket} package. * @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.http.websocket.WebSocketFrame */ @Deprecated @Sharable public class WebSocketFrameEncoder extends OneToOneEncoder { @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) msg; int type = frame.getType(); if (frame.isText()) { // Text frame ChannelBuffer data = frame.getBinaryData(); ChannelBuffer encoded = channel.getConfig().getBufferFactory().getBuffer( data.order(), data.readableBytes() + 2); encoded.writeByte((byte) type); encoded.writeBytes(data, data.readerIndex(), data.readableBytes()); encoded.writeByte((byte) 0xFF); return encoded; } else { // Binary frame ChannelBuffer data = frame.getBinaryData(); int dataLen = data.readableBytes(); ChannelBuffer encoded = channel.getConfig().getBufferFactory().getBuffer( data.order(), dataLen + 5); // Encode type. encoded.writeByte((byte) type); // Encode length. int b1 = dataLen >>> 28 & 0x7F; int b2 = dataLen >>> 14 & 0x7F; int b3 = dataLen >>> 7 & 0x7F; int b4 = dataLen & 0x7F; if (b1 == 0) { if (b2 == 0) { if (b3 == 0) { encoded.writeByte(b4); } else { encoded.writeByte(b3 | 0x80); encoded.writeByte(b4); } } else { encoded.writeByte(b2 | 0x80); encoded.writeByte(b3 | 0x80); encoded.writeByte(b4); } } else { encoded.writeByte(b1 | 0x80); encoded.writeByte(b2 | 0x80); encoded.writeByte(b3 | 0x80); encoded.writeByte(b4); } // Encode binary data. encoded.writeBytes(data, data.readerIndex(), dataLen); return encoded; } } return msg; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocket/package-info.java000066400000000000000000000023571225554127700334340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * @deprecated Use org.jboss.netty.handler.codec.http.websocketx instead. * * Encoder, decoder and their related message types for * Web Socket data frames. *

* For the detailed instruction on adding add Web Socket support to your HTTP * server, take a look into the WebSocketServer example located in the * {@code org.jboss.netty.example.http.websocket} package. * * * @apiviz.exclude OneToOne(Encoder|Decoder)$ * @apiviz.exclude \.codec\.replay\. * @apiviz.exclude \.Default */ package org.jboss.netty.handler.codec.http.websocket; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/000077500000000000000000000000001225554127700304265ustar00rootroot00000000000000BinaryWebSocketFrame.java000066400000000000000000000037661225554127700352340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * Web Socket frame containing binary data */ public class BinaryWebSocketFrame extends WebSocketFrame { /** * Creates a new empty binary frame. */ public BinaryWebSocketFrame() { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new binary frame with the specified binary data. The final fragment flag is set to true. * * @param binaryData * the content of the frame. */ public BinaryWebSocketFrame(ChannelBuffer binaryData) { setBinaryData(binaryData); } /** * Creates a new binary frame with the specified binary data and the final fragment flag. * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. */ public BinaryWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); setBinaryData(binaryData); } @Override public String toString() { return getClass().getSimpleName() + "(data: " + getBinaryData() + ')'; } } CloseWebSocketFrame.java000066400000000000000000000122431225554127700350430ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import java.io.UnsupportedEncodingException; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.CharsetUtil; /** * Web Socket Frame for closing the connection */ public class CloseWebSocketFrame extends WebSocketFrame { /** * Creates a new empty close frame. */ public CloseWebSocketFrame() { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new empty close frame with closing status code and reason text * * @param statusCode * Integer status code as per RFC 6455. For * example, 1000 indicates normal closure. * @param reasonText * Reason text. Set to null if no text. */ public CloseWebSocketFrame(int statusCode, String reasonText) { this(true, 0, statusCode, reasonText); } /** * Creates a new close frame with no losing status code and no reason text * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions */ public CloseWebSocketFrame(boolean finalFragment, int rsv) { this(finalFragment, rsv, null); } /** * Creates a new close frame with closing status code and reason text * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param statusCode * Integer status code as per RFC 6455. For * example, 1000 indicates normal closure. * @param reasonText * Reason text. Set to null if no text. */ public CloseWebSocketFrame(boolean finalFragment, int rsv, int statusCode, String reasonText) { setFinalFragment(finalFragment); setRsv(rsv); byte[] reasonBytes = new byte[0]; if (reasonText != null) { try { reasonBytes = reasonText.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { // This should never happen, anyway provide a fallback here reasonBytes = reasonText.getBytes(); } } ChannelBuffer binaryData = ChannelBuffers.buffer(2 + reasonBytes.length); binaryData.writeShort(statusCode); if (reasonBytes.length > 0) { binaryData.writeBytes(reasonBytes); } binaryData.readerIndex(0); setBinaryData(binaryData); } /** * Creates a new close frame * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. Must be 2 byte integer followed by optional UTF-8 encoded string. */ public CloseWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); if (binaryData == null) { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { setBinaryData(binaryData); } } /** * Returns the closing status code as per RFC 6455. If * a status code is set, -1 is returned. */ public int getStatusCode() { ChannelBuffer binaryData = getBinaryData(); if (binaryData == null || binaryData.capacity() == 0) { return -1; } binaryData.readerIndex(0); int statusCode = binaryData.readShort(); binaryData.readerIndex(0); return statusCode; } /** * Returns the reason text as per RFC 6455 If a reason * text is not supplied, an empty string is returned. */ public String getReasonText() { ChannelBuffer binaryData = getBinaryData(); if (binaryData == null || binaryData.capacity() <= 2) { return ""; } binaryData.readerIndex(2); String reasonText = binaryData.toString(CharsetUtil.UTF_8); binaryData.readerIndex(0); return reasonText; } @Override public String toString() { return getClass().getSimpleName(); } } ContinuationWebSocketFrame.java000066400000000000000000000105541225554127700364530ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.CharsetUtil; /** * Web Socket continuation frame containing continuation text or binary data. This is used for * fragmented messages where the contents of a messages is contained more than 1 frame. */ public class ContinuationWebSocketFrame extends WebSocketFrame { private String aggregatedText; /** * Creates a new empty continuation frame. */ public ContinuationWebSocketFrame() { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new continuation frame with the specified binary data. The final fragment flag is * set to true. * * @param binaryData * the content of the frame. */ public ContinuationWebSocketFrame(ChannelBuffer binaryData) { setBinaryData(binaryData); } /** * Creates a new continuation frame with the specified binary data * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. */ public ContinuationWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); setBinaryData(binaryData); } /** * Creates a new continuation frame with the specified binary data * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. * @param aggregatedText * Aggregated text set by decoder on the final continuation frame of a fragmented text message */ public ContinuationWebSocketFrame( boolean finalFragment, int rsv, ChannelBuffer binaryData, String aggregatedText) { setFinalFragment(finalFragment); setRsv(rsv); setBinaryData(binaryData); this.aggregatedText = aggregatedText; } /** * Creates a new continuation frame with the specified text data * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param text * text content of the frame. */ public ContinuationWebSocketFrame(boolean finalFragment, int rsv, String text) { setFinalFragment(finalFragment); setRsv(rsv); setText(text); } /** * Returns the text data in this frame */ public String getText() { if (getBinaryData() == null) { return null; } return getBinaryData().toString(CharsetUtil.UTF_8); } /** * Sets the string for this frame * * @param text * text to store */ public void setText(String text) { if (text == null || text.length() == 0) { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } } @Override public String toString() { return getClass().getSimpleName() + "(data: " + getBinaryData() + ')'; } /** * Aggregated text returned by decoder on the final continuation frame of a fragmented text message */ public String getAggregatedText() { return aggregatedText; } public void setAggregatedText(String aggregatedText) { this.aggregatedText = aggregatedText; } } PingWebSocketFrame.java000066400000000000000000000037031225554127700346740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * Web Socket frame containing binary data */ public class PingWebSocketFrame extends WebSocketFrame { /** * Creates a new empty ping frame. */ public PingWebSocketFrame() { setFinalFragment(true); setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new ping frame with the specified binary data. * * @param binaryData * the content of the frame. */ public PingWebSocketFrame(ChannelBuffer binaryData) { setBinaryData(binaryData); } /** * Creates a new ping frame with the specified binary data * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. */ public PingWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); setBinaryData(binaryData); } @Override public String toString() { return getClass().getSimpleName() + "(data: " + getBinaryData() + ')'; } } PongWebSocketFrame.java000066400000000000000000000036431225554127700347050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * Web Socket frame containing binary data */ public class PongWebSocketFrame extends WebSocketFrame { /** * Creates a new empty pong frame. */ public PongWebSocketFrame() { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new pong frame with the specified binary data. * * @param binaryData * the content of the frame. */ public PongWebSocketFrame(ChannelBuffer binaryData) { setBinaryData(binaryData); } /** * Creates a new pong frame with the specified binary data * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. */ public PongWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); setBinaryData(binaryData); } @Override public String toString() { return getClass().getSimpleName() + "(data: " + getBinaryData() + ')'; } } TextWebSocketFrame.java000066400000000000000000000074301225554127700347240ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.CharsetUtil; /** * Web Socket text frame with assumed UTF-8 encoding */ public class TextWebSocketFrame extends WebSocketFrame { /** * Creates a new empty text frame. */ public TextWebSocketFrame() { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** * Creates a new text frame with the specified text string. The final fragment flag is set to true. * * @param text * String to put in the frame */ public TextWebSocketFrame(String text) { if (text == null || text.length() == 0) { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } } /** * Creates a new text frame with the specified binary data. The final fragment flag is set to true. * * @param binaryData * the content of the frame. Must be UTF-8 encoded */ public TextWebSocketFrame(ChannelBuffer binaryData) { setBinaryData(binaryData); } /** * Creates a new text frame with the specified text string. The final fragment flag is set to true. * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param text * String to put in the frame */ public TextWebSocketFrame(boolean finalFragment, int rsv, String text) { setFinalFragment(finalFragment); setRsv(rsv); if (text == null || text.length() == 0) { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } } /** * Creates a new text frame with the specified binary data. The final fragment flag is set to true. * * @param finalFragment * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions * @param binaryData * the content of the frame. Must be UTF-8 encoded */ public TextWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); setBinaryData(binaryData); } /** * Returns the text data in this frame */ public String getText() { if (getBinaryData() == null) { return null; } return getBinaryData().toString(CharsetUtil.UTF_8); } /** * Sets the string for this frame * * @param text * text to store */ public void setText(String text) { if (text == null) { throw new NullPointerException("text"); } setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } @Override public String toString() { return getClass().getSimpleName() + "(text: " + getText() + ')'; } } UTF8Exception.java000066400000000000000000000040771225554127700336270ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Adaptation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ * * Copyright (c) 2008-2009 Bjoern Hoehrmann * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.jboss.netty.handler.codec.http.websocketx; /** * Invalid UTF8 bytes encountered */ final class UTF8Exception extends RuntimeException { private static final long serialVersionUID = 1L; UTF8Exception(String reason) { super(reason); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/UTF8Output.java000066400000000000000000000106631225554127700332460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Adaptation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ * * Copyright (c) 2008-2009 Bjoern Hoehrmann * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.jboss.netty.handler.codec.http.websocketx; /** * Checks UTF8 bytes for validity before converting it into a string */ final class UTF8Output { private static final int UTF8_ACCEPT = 0; private static final int UTF8_REJECT = 12; private static final byte[] TYPES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; private static final byte[] STATES = { 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }; @SuppressWarnings("RedundantFieldInitialization") private int state = UTF8_ACCEPT; private int codep; private final StringBuilder stringBuilder; UTF8Output(byte[] bytes) { stringBuilder = new StringBuilder(bytes.length); write(bytes); } public void write(byte[] bytes) { for (byte b : bytes) { write(b); } } public void write(int b) { byte type = TYPES[b & 0xFF]; codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b; state = STATES[state + type]; if (state == UTF8_ACCEPT) { stringBuilder.append((char) codep); } else if (state == UTF8_REJECT) { throw new UTF8Exception("bytes are not UTF-8"); } } @Override public String toString() { if (state != UTF8_ACCEPT) { throw new UTF8Exception("bytes are not UTF-8"); } return stringBuilder.toString(); } } WebSocket00FrameDecoder.java000066400000000000000000000122601225554127700355020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.handler.codec.replay.VoidEnum; /** * Decodes {@link ChannelBuffer}s into {@link WebSocketFrame}s. *

* For the detailed instruction on adding add Web Socket support to your HTTP server, take a look into the * WebSocketServer example located in the {@code org.jboss.netty.example.http.websocket} package. * * @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.http.websocket.WebSocketFrame */ public class WebSocket00FrameDecoder extends ReplayingDecoder { private static final long DEFAULT_MAX_FRAME_SIZE = 16384; private final long maxFrameSize; private boolean receivedClosingHandshake; public WebSocket00FrameDecoder() { this(DEFAULT_MAX_FRAME_SIZE); } /** * Creates a new instance of {@code WebSocketFrameDecoder} with the specified {@code maxFrameSize}. If the client * sends a frame size larger than {@code maxFrameSize}, the channel will be closed. * * @param maxFrameSize * the maximum frame size to decode * @deprecated */ @Deprecated public WebSocket00FrameDecoder(int maxFrameSize) { this.maxFrameSize = maxFrameSize; } /** * Creates a new instance of {@code WebSocketFrameDecoder} with the specified {@code maxFrameSize}. If the client * sends a frame size larger than {@code maxFrameSize}, the channel will be closed. * * @param maxFrameSize * the maximum frame size to decode */ public WebSocket00FrameDecoder(long maxFrameSize) { this.maxFrameSize = maxFrameSize; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { // Discard all data received if closing handshake was received before. if (receivedClosingHandshake) { buffer.skipBytes(actualReadableBytes()); return null; } // Decode a frame otherwise. byte type = buffer.readByte(); if ((type & 0x80) == 0x80) { // If the MSB on type is set, decode the frame length return decodeBinaryFrame(type, buffer); } else { // Decode a 0xff terminated UTF-8 string return decodeTextFrame(buffer); } } private WebSocketFrame decodeBinaryFrame(byte type, ChannelBuffer buffer) throws TooLongFrameException { long frameSize = 0; int lengthFieldSize = 0; byte b; do { b = buffer.readByte(); frameSize <<= 7; frameSize |= b & 0x7f; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } lengthFieldSize++; if (lengthFieldSize > 8) { // Perhaps a malicious peer? throw new TooLongFrameException(); } } while ((b & 0x80) == 0x80); if (type == (byte) 0xFF && frameSize == 0) { receivedClosingHandshake = true; return new CloseWebSocketFrame(); } return new BinaryWebSocketFrame(buffer.readBytes((int) frameSize)); } private WebSocketFrame decodeTextFrame(ChannelBuffer buffer) throws TooLongFrameException { int ridx = buffer.readerIndex(); int rbytes = actualReadableBytes(); int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF); if (delimPos == -1) { // Frame delimiter (0xFF) not found if (rbytes > maxFrameSize) { // Frame length exceeded the maximum throw new TooLongFrameException(); } else { // Wait until more data is received return null; } } int frameSize = delimPos - ridx; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } ChannelBuffer binaryData = buffer.readBytes(frameSize); buffer.skipBytes(1); int ffDelimPos = binaryData.indexOf(binaryData.readerIndex(), binaryData.writerIndex(), (byte) 0xFF); if (ffDelimPos >= 0) { throw new IllegalArgumentException("a text frame should not contain 0xFF."); } return new TextWebSocketFrame(binaryData); } } WebSocket00FrameEncoder.java000066400000000000000000000077571225554127700355330ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * Encodes a {@link WebSocketFrame} into a {@link ChannelBuffer}. *

* For the detailed instruction on adding add Web Socket support to your HTTP server, take a look into the * WebSocketServer example located in the {@code org.jboss.netty.example.http.websocket} package. * * @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.codec.http.websocket.WebSocketFrame */ @Sharable public class WebSocket00FrameEncoder extends OneToOneEncoder { @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) msg; if (frame instanceof TextWebSocketFrame) { // Text frame ChannelBuffer data = frame.getBinaryData(); ChannelBuffer encoded = channel.getConfig().getBufferFactory() .getBuffer(data.order(), data.readableBytes() + 2); encoded.writeByte((byte) 0x00); encoded.writeBytes(data, data.readerIndex(), data.readableBytes()); encoded.writeByte((byte) 0xFF); return encoded; } else if (frame instanceof CloseWebSocketFrame) { // Close frame ChannelBuffer data = frame.getBinaryData(); ChannelBuffer encoded = channel.getConfig().getBufferFactory().getBuffer(data.order(), 2); encoded.writeByte((byte) 0xFF); encoded.writeByte((byte) 0x00); return encoded; } else { // Binary frame ChannelBuffer data = frame.getBinaryData(); int dataLen = data.readableBytes(); ChannelBuffer encoded = channel.getConfig().getBufferFactory().getBuffer(data.order(), dataLen + 5); // Encode type. encoded.writeByte((byte) 0x80); // Encode length. int b1 = dataLen >>> 28 & 0x7F; int b2 = dataLen >>> 14 & 0x7F; int b3 = dataLen >>> 7 & 0x7F; int b4 = dataLen & 0x7F; if (b1 == 0) { if (b2 == 0) { if (b3 == 0) { encoded.writeByte(b4); } else { encoded.writeByte(b3 | 0x80); encoded.writeByte(b4); } } else { encoded.writeByte(b2 | 0x80); encoded.writeByte(b3 | 0x80); encoded.writeByte(b4); } } else { encoded.writeByte(b1 | 0x80); encoded.writeByte(b2 | 0x80); encoded.writeByte(b3 | 0x80); encoded.writeByte(b4); } // Encode binary data. encoded.writeBytes(data, data.readerIndex(), dataLen); return encoded; } } return msg; } } WebSocket07FrameDecoder.java000066400000000000000000000062751225554127700355220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other // materials provided with the distribution. // // * Neither the name of the Webbit nor the names of // its contributors may be used to endorse or promote products // derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package org.jboss.netty.handler.codec.http.websocketx; /** * Decodes a web socket frame from wire protocol version 7 format. V7 is essentially the same as V8. */ public class WebSocket07FrameDecoder extends WebSocket08FrameDecoder { /** * Constructor * * @param maskedPayload * Web socket servers must set this to true processed incoming masked payload. Client implementations * must set this to false. * @param allowExtensions * Flag to allow reserved extension bits to be used or not * @param maxFramePayloadLength * Maximum length of a frame's payload. Setting this to an appropriate value for you application * helps check for denial of services attacks. */ public WebSocket07FrameDecoder(boolean maskedPayload, boolean allowExtensions, long maxFramePayloadLength) { super(maskedPayload, allowExtensions, maxFramePayloadLength); } } WebSocket07FrameEncoder.java000066400000000000000000000054341225554127700355300ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other // materials provided with the distribution. // // * Neither the name of the Webbit nor the names of // its contributors may be used to endorse or promote products // derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package org.jboss.netty.handler.codec.http.websocketx; /** *

* Encodes a web socket frame into wire protocol version 7 format. V7 is essentially the same as V8. *

*/ public class WebSocket07FrameEncoder extends WebSocket08FrameEncoder { /** * Constructor * * @param maskPayload * Web socket clients must set this to true to mask payload. Server implementations must set this to * false. */ public WebSocket07FrameEncoder(boolean maskPayload) { super(maskPayload); } } WebSocket08FrameDecoder.java000066400000000000000000000451501225554127700355160ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other // materials provided with the distribution. // // * Neither the name of the Webbit nor the names of // its contributors may be used to endorse or promote products // derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.CorruptedFrameException; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * Decodes a web socket frame from wire protocol version 8 format. This code was forked from webbit and modified. */ public class WebSocket08FrameDecoder extends ReplayingDecoder { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocket08FrameDecoder.class); private static final byte OPCODE_CONT = 0x0; private static final byte OPCODE_TEXT = 0x1; private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_CLOSE = 0x8; private static final byte OPCODE_PING = 0x9; private static final byte OPCODE_PONG = 0xA; private UTF8Output fragmentedFramesText; private int fragmentedFramesCount; private final long maxFramePayloadLength; private boolean frameFinalFlag; private int frameRsv; private int frameOpcode; private long framePayloadLength; private ChannelBuffer framePayload; private int framePayloadBytesRead; private ChannelBuffer maskingKey; private final boolean allowExtensions; private final boolean maskedPayload; private boolean receivedClosingHandshake; public enum State { FRAME_START, MASKING_KEY, PAYLOAD, CORRUPT } /** * Constructor with default values * * @param maskedPayload * Web socket servers must set this to true processed incoming masked payload. Client implementations * must set this to false. * @param allowExtensions * Flag to allow reserved extension bits to be used or not */ public WebSocket08FrameDecoder(boolean maskedPayload, boolean allowExtensions) { this(maskedPayload, allowExtensions, Long.MAX_VALUE); } /** * Constructor * * @param maskedPayload * Web socket servers must set this to true processed incoming masked payload. Client implementations * must set this to false. * @param allowExtensions * Flag to allow reserved extension bits to be used or not * @param maxFramePayloadLength * Maximum length of a frame's payload. Setting this to an appropriate value for you application * helps check for denial of services attacks. */ public WebSocket08FrameDecoder(boolean maskedPayload, boolean allowExtensions, long maxFramePayloadLength) { super(State.FRAME_START); this.maskedPayload = maskedPayload; this.allowExtensions = allowExtensions; this.maxFramePayloadLength = maxFramePayloadLength; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { // Discard all data received if closing handshake was received before. if (receivedClosingHandshake) { buffer.skipBytes(actualReadableBytes()); return null; } switch (state) { case FRAME_START: framePayloadBytesRead = 0; framePayloadLength = -1; framePayload = null; // FIN, RSV, OPCODE byte b = buffer.readByte(); frameFinalFlag = (b & 0x80) != 0; frameRsv = (b & 0x70) >> 4; frameOpcode = b & 0x0F; if (logger.isDebugEnabled()) { logger.debug("Decoding WebSocket Frame opCode=" + frameOpcode); } // MASK, PAYLOAD LEN 1 b = buffer.readByte(); boolean frameMasked = (b & 0x80) != 0; int framePayloadLen1 = b & 0x7F; if (frameRsv != 0 && !allowExtensions) { protocolViolation(channel, "RSV != 0 and no extension negotiated, RSV:" + frameRsv); return null; } if (maskedPayload && !frameMasked) { protocolViolation(channel, "unmasked client to server frame"); return null; } if (frameOpcode > 7) { // control frame (have MSB in opcode set) // control frames MUST NOT be fragmented if (!frameFinalFlag) { protocolViolation(channel, "fragmented control frame"); return null; } // control frames MUST have payload 125 octets or less if (framePayloadLen1 > 125) { protocolViolation(channel, "control frame with payload length > 125 octets"); return null; } // check for reserved control frame opcodes if (!(frameOpcode == OPCODE_CLOSE || frameOpcode == OPCODE_PING || frameOpcode == OPCODE_PONG)) { protocolViolation(channel, "control frame using reserved opcode " + frameOpcode); return null; } // close frame : if there is a body, the first two bytes of the // body MUST be a 2-byte unsigned integer (in network byte // order) representing a status code if (frameOpcode == 8 && framePayloadLen1 == 1) { protocolViolation(channel, "received close control frame with payload len 1"); return null; } } else { // data frame // check for reserved data frame opcodes if (!(frameOpcode == OPCODE_CONT || frameOpcode == OPCODE_TEXT || frameOpcode == OPCODE_BINARY)) { protocolViolation(channel, "data frame using reserved opcode " + frameOpcode); return null; } // check opcode vs message fragmentation state 1/2 if (fragmentedFramesCount == 0 && frameOpcode == OPCODE_CONT) { protocolViolation(channel, "received continuation data frame outside fragmented message"); return null; } // check opcode vs message fragmentation state 2/2 if (fragmentedFramesCount != 0 && frameOpcode != OPCODE_CONT && frameOpcode != OPCODE_PING) { protocolViolation(channel, "received non-continuation data frame while inside fragmented message"); return null; } } // Read frame payload length if (framePayloadLen1 == 126) { framePayloadLength = buffer.readUnsignedShort(); if (framePayloadLength < 126) { protocolViolation(channel, "invalid data frame length (not using minimal length encoding)"); return null; } } else if (framePayloadLen1 == 127) { framePayloadLength = buffer.readLong(); // TODO: check if it's bigger than 0x7FFFFFFFFFFFFFFF, Maybe // just check if it's negative? if (framePayloadLength < 65536) { protocolViolation(channel, "invalid data frame length (not using minimal length encoding)"); return null; } } else { framePayloadLength = framePayloadLen1; } if (framePayloadLength > maxFramePayloadLength) { protocolViolation(channel, "Max frame length of " + maxFramePayloadLength + " has been exceeded."); return null; } if (logger.isDebugEnabled()) { logger.debug("Decoding WebSocket Frame length=" + framePayloadLength); } checkpoint(State.MASKING_KEY); case MASKING_KEY: if (maskedPayload) { maskingKey = buffer.readBytes(4); } checkpoint(State.PAYLOAD); case PAYLOAD: // Sometimes, the payload may not be delivered in 1 nice packet // We need to accumulate the data until we have it all int rbytes = actualReadableBytes(); ChannelBuffer payloadBuffer = null; long willHaveReadByteCount = framePayloadBytesRead + rbytes; // logger.debug("Frame rbytes=" + rbytes + " willHaveReadByteCount=" // + willHaveReadByteCount + " framePayloadLength=" + // framePayloadLength); if (willHaveReadByteCount == framePayloadLength) { // We have all our content so proceed to process payloadBuffer = buffer.readBytes(rbytes); } else if (willHaveReadByteCount < framePayloadLength) { // We don't have all our content so accumulate payload. // Returning null means we will get called back payloadBuffer = buffer.readBytes(rbytes); if (framePayload == null) { framePayload = channel.getConfig().getBufferFactory().getBuffer(toFrameLength(framePayloadLength)); } framePayload.writeBytes(payloadBuffer); framePayloadBytesRead += rbytes; // Return null to wait for more bytes to arrive return null; } else if (willHaveReadByteCount > framePayloadLength) { // We have more than what we need so read up to the end of frame // Leave the remainder in the buffer for next frame payloadBuffer = buffer.readBytes(toFrameLength(framePayloadLength - framePayloadBytesRead)); } // Now we have all the data, the next checkpoint must be the next // frame checkpoint(State.FRAME_START); // Take the data that we have in this packet if (framePayload == null) { framePayload = payloadBuffer; } else { framePayload.writeBytes(payloadBuffer); } // Unmask data if needed if (maskedPayload) { unmask(framePayload); } // Processing ping/pong/close frames because they cannot be // fragmented if (frameOpcode == OPCODE_PING) { return new PingWebSocketFrame(frameFinalFlag, frameRsv, framePayload); } if (frameOpcode == OPCODE_PONG) { return new PongWebSocketFrame(frameFinalFlag, frameRsv, framePayload); } if (frameOpcode == OPCODE_CLOSE) { checkCloseFrameBody(channel, framePayload); receivedClosingHandshake = true; return new CloseWebSocketFrame(frameFinalFlag, frameRsv, framePayload); } // Processing for possible fragmented messages for text and binary // frames String aggregatedText = null; if (frameFinalFlag) { // Final frame of the sequence. Apparently ping frames are // allowed in the middle of a fragmented message if (frameOpcode != OPCODE_PING) { fragmentedFramesCount = 0; // Check text for UTF8 correctness if (frameOpcode == OPCODE_TEXT || fragmentedFramesText != null) { // Check UTF-8 correctness for this payload checkUTF8String(channel, framePayload.array()); // This does a second check to make sure UTF-8 // correctness for entire text message aggregatedText = fragmentedFramesText.toString(); fragmentedFramesText = null; } } } else { // Not final frame so we can expect more frames in the // fragmented sequence if (fragmentedFramesCount == 0) { // First text or binary frame for a fragmented set fragmentedFramesText = null; if (frameOpcode == OPCODE_TEXT) { checkUTF8String(channel, framePayload.array()); } } else { // Subsequent frames - only check if init frame is text if (fragmentedFramesText != null) { checkUTF8String(channel, framePayload.array()); } } // Increment counter fragmentedFramesCount++; } // Return the frame if (frameOpcode == OPCODE_TEXT) { return new TextWebSocketFrame(frameFinalFlag, frameRsv, framePayload); } else if (frameOpcode == OPCODE_BINARY) { return new BinaryWebSocketFrame(frameFinalFlag, frameRsv, framePayload); } else if (frameOpcode == OPCODE_CONT) { return new ContinuationWebSocketFrame(frameFinalFlag, frameRsv, framePayload, aggregatedText); } else { throw new UnsupportedOperationException("Cannot decode web socket frame with opcode: " + frameOpcode); } case CORRUPT: // If we don't keep reading Netty will throw an exception saying // we can't return null if no bytes read and state not changed. buffer.readByte(); return null; default: throw new Error("Shouldn't reach here."); } } private void unmask(ChannelBuffer frame) { byte[] bytes = frame.array(); for (int i = 0; i < bytes.length; i++) { frame.setByte(i, frame.getByte(i) ^ maskingKey.getByte(i % 4)); } } private void protocolViolation(Channel channel, String reason) throws CorruptedFrameException { checkpoint(State.CORRUPT); if (channel.isConnected()) { channel.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } throw new CorruptedFrameException(reason); } private static int toFrameLength(long l) throws TooLongFrameException { if (l > Integer.MAX_VALUE) { throw new TooLongFrameException("Length:" + l); } else { return (int) l; } } private void checkUTF8String(Channel channel, byte[] bytes) throws CorruptedFrameException { try { // StringBuilder sb = new StringBuilder("UTF8 " + bytes.length + // " bytes: "); // for (byte b : bytes) { // sb.append(Integer.toHexString(b)).append(" "); // } // logger.debug(sb.toString()); if (fragmentedFramesText == null) { fragmentedFramesText = new UTF8Output(bytes); } else { fragmentedFramesText.write(bytes); } } catch (UTF8Exception ex) { protocolViolation(channel, "invalid UTF-8 bytes"); } } protected void checkCloseFrameBody(Channel channel, ChannelBuffer buffer) throws CorruptedFrameException { if (buffer == null || buffer.capacity() == 0) { return; } if (buffer.capacity() == 1) { protocolViolation(channel, "Invalid close frame body"); } // Save reader index int idx = buffer.readerIndex(); buffer.readerIndex(0); // Must have 2 byte integer within the valid range int statusCode = buffer.readShort(); if (statusCode >= 0 && statusCode <= 999 || statusCode >= 1004 && statusCode <= 1006 || statusCode >= 1012 && statusCode <= 2999) { protocolViolation(channel, "Invalid close frame status code: " + statusCode); } // May have UTF-8 message if (buffer.readableBytes() > 0) { byte[] b = new byte[buffer.readableBytes()]; buffer.readBytes(b); try { new UTF8Output(b); } catch (UTF8Exception ex) { protocolViolation(channel, "Invalid close frame reason text. Invalid UTF-8 bytes"); } } // Restore reader index buffer.readerIndex(idx); } } WebSocket08FrameEncoder.java000066400000000000000000000161561225554127700355340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other // materials provided with the distribution. // // * Neither the name of the Webbit nor the names of // its contributors may be used to endorse or promote products // derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.nio.ByteBuffer; /** *

* Encodes a web socket frame into wire protocol version 8 format. This code was forked from webbit and modified. *

*/ public class WebSocket08FrameEncoder extends OneToOneEncoder { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocket08FrameEncoder.class); private static final byte OPCODE_CONT = 0x0; private static final byte OPCODE_TEXT = 0x1; private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_CLOSE = 0x8; private static final byte OPCODE_PING = 0x9; private static final byte OPCODE_PONG = 0xA; private final boolean maskPayload; /** * Constructor * * @param maskPayload * Web socket clients must set this to true to mask payload. Server implementations must set this to * false. */ public WebSocket08FrameEncoder(boolean maskPayload) { this.maskPayload = maskPayload; } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { byte[] mask; if (msg instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) msg; ChannelBuffer data = frame.getBinaryData(); if (data == null) { data = ChannelBuffers.EMPTY_BUFFER; } byte opcode; if (frame instanceof TextWebSocketFrame) { opcode = OPCODE_TEXT; } else if (frame instanceof PingWebSocketFrame) { opcode = OPCODE_PING; } else if (frame instanceof PongWebSocketFrame) { opcode = OPCODE_PONG; } else if (frame instanceof CloseWebSocketFrame) { opcode = OPCODE_CLOSE; } else if (frame instanceof BinaryWebSocketFrame) { opcode = OPCODE_BINARY; } else if (frame instanceof ContinuationWebSocketFrame) { opcode = OPCODE_CONT; } else { throw new UnsupportedOperationException("Cannot encode frame of type: " + frame.getClass().getName()); } int length = data.readableBytes(); if (logger.isDebugEnabled()) { logger.debug("Encoding WebSocket Frame opCode=" + opcode + " length=" + length); } int b0 = 0; if (frame.isFinalFragment()) { b0 |= 1 << 7; } b0 |= frame.getRsv() % 8 << 4; b0 |= opcode % 128; ChannelBuffer header; ChannelBuffer body; if (opcode == OPCODE_PING && length > 125) { throw new TooLongFrameException("invalid payload for PING (payload length must be <= 125, was " + length); } int maskLength = maskPayload ? 4 : 0; if (length <= 125) { header = ChannelBuffers.buffer(2 + maskLength); header.writeByte(b0); byte b = (byte) (maskPayload ? 0x80 | (byte) length : (byte) length); header.writeByte(b); } else if (length <= 0xFFFF) { header = ChannelBuffers.buffer(4 + maskLength); header.writeByte(b0); header.writeByte(maskPayload ? 0xFE : 126); header.writeByte(length >>> 8 & 0xFF); header.writeByte(length & 0xFF); } else { header = ChannelBuffers.buffer(10 + maskLength); header.writeByte(b0); header.writeByte(maskPayload ? 0xFF : 127); header.writeLong(length); } // Write payload if (maskPayload) { Integer random = (int) (Math.random() * Integer.MAX_VALUE); mask = ByteBuffer.allocate(4).putInt(random).array(); header.writeBytes(mask); body = ChannelBuffers.buffer(length); int counter = 0; while (data.readableBytes() > 0) { byte byteData = data.readByte(); body.writeByte(byteData ^ mask[counter++ % 4]); } } else { body = data; } return ChannelBuffers.wrappedBuffer(header, body); } // If not websocket, then just return the message return msg; } } WebSocket13FrameDecoder.java000066400000000000000000000073161225554127700355140ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other // materials provided with the distribution. // // * Neither the name of the Webbit nor the names of // its contributors may be used to endorse or promote products // derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package org.jboss.netty.handler.codec.http.websocketx; /** * Decodes a web socket frame from wire protocol version 13 format. V13 is * essentially the same as V8. */ public class WebSocket13FrameDecoder extends WebSocket08FrameDecoder { /** * Constructor with default values * * @param maskedPayload * Web socket servers must set this to true processed incoming masked payload. Client implementations * must set this to false. * @param allowExtensions * Flag to allow reserved extension bits to be used or not */ public WebSocket13FrameDecoder(boolean maskedPayload, boolean allowExtensions) { this(maskedPayload, allowExtensions, Long.MAX_VALUE); } /** * Constructor * * @param maskedPayload * Web socket servers must set this to true processed incoming * masked payload. Client implementations must set this to false. * @param allowExtensions * Flag to allow reserved extension bits to be used or not * @param maxFramePayloadLength * Maximum length of a frame's payload. Setting this to an * appropriate value for you application helps check for denial * of services attacks. */ public WebSocket13FrameDecoder(boolean maskedPayload, boolean allowExtensions, long maxFramePayloadLength) { super(maskedPayload, allowExtensions, maxFramePayloadLength); } } WebSocket13FrameEncoder.java000066400000000000000000000054361225554127700355270ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the // following disclaimer in the documentation and/or other // materials provided with the distribution. // // * Neither the name of the Webbit nor the names of // its contributors may be used to endorse or promote products // derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package org.jboss.netty.handler.codec.http.websocketx; /** *

* Encodes a web socket frame into wire protocol version 13 format. V13 is essentially the same as V8. *

*/ public class WebSocket13FrameEncoder extends WebSocket08FrameEncoder { /** * Constructor * * @param maskPayload * Web socket clients must set this to true to mask payload. Server implementations must set this to * false. */ public WebSocket13FrameEncoder(boolean maskPayload) { super(maskPayload); } } WebSocketClientHandshaker.java000066400000000000000000000116621225554127700362360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.handler.codec.http.HttpResponse; import java.net.URI; import java.util.Map; /** * Base class for web socket client handshake implementations */ public abstract class WebSocketClientHandshaker { private final URI webSocketUrl; private final WebSocketVersion version; private volatile boolean handshakeComplete; private final String expectedSubprotocol; private volatile String actualSubprotocol; protected final Map customHeaders; private final long maxFramePayloadLength; /** * Base constructor with default values * * @param webSocketUrl * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param customHeaders * Map of custom headers to add to the client request */ protected WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol, Map customHeaders) { this(webSocketUrl, version, subprotocol, customHeaders, Long.MAX_VALUE); } /** * Base constructor * * @param webSocketUrl * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * CSV of requested subprotocol(s) sent to the server. * @param customHeaders * Map of custom headers to add to the client request * @param maxFramePayloadLength * Maximum length of a frame's payload */ protected WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol, Map customHeaders, long maxFramePayloadLength) { this.webSocketUrl = webSocketUrl; this.version = version; expectedSubprotocol = subprotocol; this.customHeaders = customHeaders; this.maxFramePayloadLength = maxFramePayloadLength; } /** * Returns the URI to the web socket. e.g. "ws://myhost.com/path" */ public URI getWebSocketUrl() { return webSocketUrl; } /** * Version of the web socket specification that is being used */ public WebSocketVersion getVersion() { return version; } /** * Returns the max length for any frame's payload */ public long getMaxFramePayloadLength() { return maxFramePayloadLength; } /** * Flag to indicate if the opening handshake is complete */ public boolean isHandshakeComplete() { return handshakeComplete; } protected void setHandshakeComplete() { handshakeComplete = true; } /** * Returns the CSV of requested subprotocol(s) sent to the server as specified in the constructor */ public String getExpectedSubprotocol() { return expectedSubprotocol; } /** * Returns the subprotocol response sent by the server. Only available after end of handshake. * Null if no subprotocol was requested or confirmed by the server. */ public String getActualSubprotocol() { return actualSubprotocol; } protected void setActualSubprotocol(String actualSubprotocol) { this.actualSubprotocol = actualSubprotocol; } /** * Begins the opening handshake * * @param channel * Channel */ public abstract ChannelFuture handshake(Channel channel) throws Exception; /** * Validates and finishes the opening handshake initiated by {@link #handshake}}. * * @param channel * Channel * @param response * HTTP response containing the closing handshake details */ public abstract void finishHandshake(Channel channel, HttpResponse response); } WebSocketClientHandshaker00.java000066400000000000000000000262711225554127700364000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpHeaders.Values; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestEncoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import java.net.URI; import java.nio.ByteBuffer; import java.util.Map; /** *

* Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 00 *

*

* A very large portion of this code was taken from the Netty 3.2 HTTP example. *

*/ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { private ChannelBuffer expectedChallengeResponseBytes; /** * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param customHeaders * Map of custom headers to add to the client request */ public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol, Map customHeaders) { this(webSocketURL, version, subprotocol, customHeaders, Long.MAX_VALUE); } /** * Constructor * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param customHeaders * Map of custom headers to add to the client request * @param maxFramePayloadLength * Maximum length of a frame's payload */ public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol, Map customHeaders, long maxFramePayloadLength) { super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); } /** *

* Sends the opening request to the server: *

* *
     * GET /demo HTTP/1.1
     * Upgrade: WebSocket
     * Connection: Upgrade
     * Host: example.com
     * Origin: http://example.com
     * Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
     * Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
     *
     * ^n:ds[4U
     * 
* * @param channel * Channel into which we can write our request */ @Override public ChannelFuture handshake(Channel channel) { // Make keys int spaces1 = WebSocketUtil.randomNumber(1, 12); int spaces2 = WebSocketUtil.randomNumber(1, 12); int max1 = Integer.MAX_VALUE / spaces1; int max2 = Integer.MAX_VALUE / spaces2; int number1 = WebSocketUtil.randomNumber(0, max1); int number2 = WebSocketUtil.randomNumber(0, max2); int product1 = number1 * spaces1; int product2 = number2 * spaces2; String key1 = Integer.toString(product1); String key2 = Integer.toString(product2); key1 = insertRandomCharacters(key1); key2 = insertRandomCharacters(key2); key1 = insertSpaces(key1, spaces1); key2 = insertSpaces(key2, spaces2); byte[] key3 = WebSocketUtil.randomBytes(8); ByteBuffer buffer = ByteBuffer.allocate(4); buffer.putInt(number1); byte[] number1Array = buffer.array(); buffer = ByteBuffer.allocate(4); buffer.putInt(number2); byte[] number2Array = buffer.array(); byte[] challenge = new byte[16]; System.arraycopy(number1Array, 0, challenge, 0, 4); System.arraycopy(number2Array, 0, challenge, 4, 4); System.arraycopy(key3, 0, challenge, 8, 8); expectedChallengeResponseBytes = WebSocketUtil.md5(ChannelBuffers.wrappedBuffer(challenge)); // Get path URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + '?' + wsURL.getQuery(); } if (path == null || path.length() == 0) { path = "/"; } // Format request HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); request.headers().add(Names.UPGRADE, Values.WEBSOCKET); request.headers().add(Names.CONNECTION, Values.UPGRADE); request.headers().add(Names.HOST, wsURL.getHost()); int wsPort = wsURL.getPort(); String originValue = "http://" + wsURL.getHost(); if (wsPort != 80 && wsPort != 443) { // if the port is not standard (80/443) its needed to add the port to the header. // See http://tools.ietf.org/html/rfc6454#section-6.2 originValue = originValue + ':' + wsPort; } request.headers().add(Names.ORIGIN, originValue); request.headers().add(Names.SEC_WEBSOCKET_KEY1, key1); request.headers().add(Names.SEC_WEBSOCKET_KEY2, key2); String expectedSubprotocol = getExpectedSubprotocol(); if (expectedSubprotocol != null && expectedSubprotocol.length() != 0) { request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); } if (customHeaders != null) { for (Map.Entry e: customHeaders.entrySet()) { request.headers().add(e.getKey(), e.getValue()); } } // Set Content-Length to workaround some known defect. // See also: http://www.ietf.org/mail-archive/web/hybi/current/msg02149.html request.headers().set(Names.CONTENT_LENGTH, key3.length); request.setContent(ChannelBuffers.copiedBuffer(key3)); final ChannelFuture handshakeFuture = new DefaultChannelFuture(channel, false); ChannelFuture future = channel.write(request); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { ChannelPipeline p = future.getChannel().getPipeline(); p.replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket00FrameEncoder()); if (future.isSuccess()) { handshakeFuture.setSuccess(); } else { handshakeFuture.setFailure(future.getCause()); } } }); return handshakeFuture; } /** *

* Process server response: *

* *
     * HTTP/1.1 101 WebSocket Protocol Handshake
     * Upgrade: WebSocket
     * Connection: Upgrade
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Location: ws://example.com/demo
     * Sec-WebSocket-Protocol: sample
     *
     * 8jKS'y:G*Co,Wxa-
     * 
* * @param channel * Channel * @param response * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override public void finishHandshake(Channel channel, HttpResponse response) { final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake"); if (!response.getStatus().equals(status)) { throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus()); } String upgrade = response.headers().get(Names.UPGRADE); if (!Values.WEBSOCKET.equals(upgrade)) { throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade); } String connection = response.headers().get(Names.CONNECTION); if (!Values.UPGRADE.equals(connection)) { throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection); } ChannelBuffer challenge = response.getContent(); if (!challenge.equals(expectedChallengeResponseBytes)) { throw new WebSocketHandshakeException("Invalid challenge"); } String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); setActualSubprotocol(subprotocol); setHandshakeComplete(); channel.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket00FrameDecoder(getMaxFramePayloadLength())); } private static String insertRandomCharacters(String key) { int count = WebSocketUtil.randomNumber(1, 12); char[] randomChars = new char[count]; int randCount = 0; while (randCount < count) { int rand = (int) (Math.random() * 0x7e + 0x21); if (0x21 < rand && rand < 0x2f || 0x3a < rand && rand < 0x7e) { randomChars[randCount] = (char) rand; randCount += 1; } } for (int i = 0; i < count; i++) { int split = WebSocketUtil.randomNumber(0, key.length()); String part1 = key.substring(0, split); String part2 = key.substring(split); key = part1 + randomChars[i] + part2; } return key; } private static String insertSpaces(String key, int spaces) { for (int i = 0; i < spaces; i++) { int split = WebSocketUtil.randomNumber(1, key.length() - 1); String part1 = key.substring(0, split); String part2 = key.substring(split); key = part1 + ' ' + part2; } return key; } } WebSocketClientHandshaker07.java000066400000000000000000000223171225554127700364040ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpHeaders.Values; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestEncoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import java.net.URI; import java.util.Map; /** *

* Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 07 *

*/ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker07.class); public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private String expectedChallengeResponseString; private final boolean allowExtensions; /** * Creates a new instance. * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Map of custom headers to add to the client request * @param maxFramePayloadLength * Maximum length of a frame's payload */ public WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) { super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); this.allowExtensions = allowExtensions; } /** * /** *

* Sends the opening request to the server: *

* *
     * GET /chat HTTP/1.1
     * Host: server.example.com
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, superchat
     * Sec-WebSocket-Version: 7
     * 
* * @param channel * Channel into which we can write our request */ @Override public ChannelFuture handshake(Channel channel) { // Get path URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + '?' + wsURL.getQuery(); } if (path == null || path.length() == 0) { path = "/"; } // Get 16 bit nonce and base 64 encode it byte[] nonce = WebSocketUtil.randomBytes(16); String key = WebSocketUtil.base64(ChannelBuffers.wrappedBuffer(nonce)); String acceptSeed = key + MAGIC_GUID; ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII)); expectedChallengeResponseString = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug(String.format("WS Version 07 Client Handshake key: %s. Expected response: %s.", key, expectedChallengeResponseString)); } // Format request HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase()); request.headers().add(Names.CONNECTION, Values.UPGRADE); request.headers().add(Names.SEC_WEBSOCKET_KEY, key); request.headers().add(Names.HOST, wsURL.getHost()); int wsPort = wsURL.getPort(); String originValue = "http://" + wsURL.getHost(); if (wsPort != 80 && wsPort != 443) { // if the port is not standard (80/443) its needed to add the port to the header. // See http://tools.ietf.org/html/rfc6454#section-6.2 originValue = originValue + ':' + wsPort; } request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue); String expectedSubprotocol = getExpectedSubprotocol(); if (expectedSubprotocol != null && expectedSubprotocol.length() > 0) { request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); } request.headers().add(Names.SEC_WEBSOCKET_VERSION, "7"); if (customHeaders != null) { for (Map.Entry e : customHeaders.entrySet()) { request.headers().add(e.getKey(), e.getValue()); } } final ChannelFuture handshakeFuture = new DefaultChannelFuture(channel, false); ChannelFuture future = channel.write(request); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { ChannelPipeline p = future.getChannel().getPipeline(); p.addAfter( p.getContext(HttpRequestEncoder.class).getName(), "ws-encoder", new WebSocket07FrameEncoder(true)); if (future.isSuccess()) { handshakeFuture.setSuccess(); } else { handshakeFuture.setFailure(future.getCause()); } } }); return handshakeFuture; } /** *

* Process server response: *

* *
     * HTTP/1.1 101 Switching Protocols
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
     * Sec-WebSocket-Protocol: chat
     * 
* * @param channel * Channel * @param response * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override public void finishHandshake(Channel channel, HttpResponse response) { final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS; if (!response.getStatus().equals(status)) { throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus()); } String upgrade = response.headers().get(Names.UPGRADE); if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) { throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + response.headers().get(Names.UPGRADE)); } String connection = response.headers().get(Names.CONNECTION); if (!Values.UPGRADE.equalsIgnoreCase(connection)) { throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.headers().get(Names.CONNECTION)); } String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT); if (accept == null || !accept.equals(expectedChallengeResponseString)) { throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString)); } String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); setActualSubprotocol(subprotocol); setHandshakeComplete(); ChannelPipeline p = channel.getPipeline(); p.get(HttpResponseDecoder.class).replace( "ws-decoder", new WebSocket07FrameDecoder(false, allowExtensions, getMaxFramePayloadLength())); } } WebSocketClientHandshaker08.java000066400000000000000000000245451225554127700364120ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpHeaders.Values; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestEncoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import java.net.URI; import java.util.Map; /** *

* Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 10 *

*/ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker08.class); public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private String expectedChallengeResponseString; private final boolean allowExtensions; /** * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Map of custom headers to add to the client request */ public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders) { this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, Long.MAX_VALUE); } /** * Constructor * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Map of custom headers to add to the client request * @param maxFramePayloadLength * Maximum length of a frame's payload */ public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) { super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); this.allowExtensions = allowExtensions; } /** * /** *

* Sends the opening request to the server: *

* *
     * GET /chat HTTP/1.1
     * Host: server.example.com
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, superchat
     * Sec-WebSocket-Version: 8
     * 
* * @param channel * Channel into which we can write our request */ @Override public ChannelFuture handshake(Channel channel) throws Exception { // Get path URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + '?' + wsURL.getQuery(); } if (path == null || path.length() == 0) { path = "/"; } // Get 16 bit nonce and base 64 encode it ChannelBuffer nonce = ChannelBuffers.wrappedBuffer(WebSocketUtil.randomBytes(16)); String key = WebSocketUtil.base64(nonce); String acceptSeed = key + MAGIC_GUID; ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII)); expectedChallengeResponseString = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug(String.format("WS Version 08 Client Handshake key: %s. Expected response: %s.", key, expectedChallengeResponseString)); } // Format request HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase()); request.headers().add(Names.CONNECTION, Values.UPGRADE); request.headers().add(Names.SEC_WEBSOCKET_KEY, key); request.headers().add(Names.HOST, wsURL.getHost()); int wsPort = wsURL.getPort(); String originValue = "http://" + wsURL.getHost(); if (wsPort != 80 && wsPort != 443) { // if the port is not standard (80/443) its needed to add the port to the header. // See http://tools.ietf.org/html/rfc6454#section-6.2 originValue = originValue + ':' + wsPort; } // Use Sec-WebSocket-Origin // See https://github.com/netty/netty/issues/264 request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue); String expectedSubprotocol = getExpectedSubprotocol(); if (expectedSubprotocol != null && expectedSubprotocol.length() != 0) { request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); } request.headers().add(Names.SEC_WEBSOCKET_VERSION, "8"); if (customHeaders != null) { for (Map.Entry e: customHeaders.entrySet()) { request.headers().add(e.getKey(), e.getValue()); } } final ChannelFuture handshakeFuture = new DefaultChannelFuture(channel, false); ChannelFuture future = channel.write(request); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { ChannelPipeline p = future.getChannel().getPipeline(); p.replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket08FrameEncoder(true)); if (future.isSuccess()) { handshakeFuture.setSuccess(); } else { handshakeFuture.setFailure(future.getCause()); } } }); return handshakeFuture; } /** *

* Process server response: *

* *
     * HTTP/1.1 101 Switching Protocols
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
     * Sec-WebSocket-Protocol: chat
     * 
* * @param channel * Channel * @param response * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override public void finishHandshake(Channel channel, HttpResponse response) { final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS; if (!response.getStatus().equals(status)) { throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus()); } String upgrade = response.headers().get(Names.UPGRADE); // Upgrade header should be matched case-insensitive. // See https://github.com/netty/netty/issues/278 if (upgrade == null || !upgrade.toLowerCase().equals(Values.WEBSOCKET.toLowerCase())) { throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + response.headers().get(Names.UPGRADE)); } // Connection header should be matched case-insensitive. // See https://github.com/netty/netty/issues/278 String connection = response.headers().get(Names.CONNECTION); if (connection == null || !connection.toLowerCase().equals(Values.UPGRADE.toLowerCase())) { throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.headers().get(Names.CONNECTION)); } String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT); if (accept == null || !accept.equals(expectedChallengeResponseString)) { throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString)); } String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); setActualSubprotocol(subprotocol); setHandshakeComplete(); channel.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, allowExtensions, getMaxFramePayloadLength())); } } WebSocketClientHandshaker13.java000066400000000000000000000244121225554127700363770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpHeaders.Values; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestEncoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import java.net.URI; import java.util.Map; /** *

* Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 17 *

*/ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker13.class); public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private String expectedChallengeResponseString; private final boolean allowExtensions; /** * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Map of custom headers to add to the client request */ public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders) { this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, Long.MAX_VALUE); } /** * Constructor * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Map of custom headers to add to the client request * @param maxFramePayloadLength * Maximum length of a frame's payload */ public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) { super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength); this.allowExtensions = allowExtensions; } /** * /** *

* Sends the opening request to the server: *

* *
     * GET /chat HTTP/1.1
     * Host: server.example.com
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, superchat
     * Sec-WebSocket-Version: 13
     * 
* * @param channel * Channel into which we can write our request */ @Override public ChannelFuture handshake(Channel channel) throws Exception { // Get path URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + '?' + wsURL.getQuery(); } if (path == null || path.length() == 0) { path = "/"; } // Get 16 bit nonce and base 64 encode it ChannelBuffer nonce = ChannelBuffers.wrappedBuffer(WebSocketUtil.randomBytes(16)); String key = WebSocketUtil.base64(nonce); String acceptSeed = key + MAGIC_GUID; ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII)); expectedChallengeResponseString = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug(String.format("WS Version 13 Client Handshake key: %s. Expected response: %s.", key, expectedChallengeResponseString)); } // Format request int wsPort = wsURL.getPort(); HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase()); request.headers().add(Names.CONNECTION, Values.UPGRADE); request.headers().add(Names.SEC_WEBSOCKET_KEY, key); request.headers().add(Names.HOST, wsURL.getHost() + ':' + wsPort); String originValue = "http://" + wsURL.getHost(); if (wsPort != 80 && wsPort != 443) { // if the port is not standard (80/443) its needed to add the port to the header. // See http://tools.ietf.org/html/rfc6454#section-6.2 originValue = originValue + ':' + wsPort; } request.headers().add(Names.ORIGIN, originValue); String expectedSubprotocol = getExpectedSubprotocol(); if (expectedSubprotocol != null && expectedSubprotocol.length() != 0) { request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); } request.headers().add(Names.SEC_WEBSOCKET_VERSION, "13"); if (customHeaders != null) { for (Map.Entry e: customHeaders.entrySet()) { request.headers().add(e.getKey(), e.getValue()); } } ChannelFuture future = channel.write(request); final ChannelFuture handshakeFuture = new DefaultChannelFuture(channel, false); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { ChannelPipeline p = future.getChannel().getPipeline(); p.replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket13FrameEncoder(true)); if (future.isSuccess()) { handshakeFuture.setSuccess(); } else { handshakeFuture.setFailure(future.getCause()); } } }); return handshakeFuture; } /** *

* Process server response: *

* *
     * HTTP/1.1 101 Switching Protocols
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
     * Sec-WebSocket-Protocol: chat
     * 
* * @param channel * Channel * @param response * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override public void finishHandshake(Channel channel, HttpResponse response) { final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS; if (!response.getStatus().equals(status)) { throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus()); } String upgrade = response.headers().get(Names.UPGRADE); // Upgrade header should be matched case-insensitive. // See https://github.com/netty/netty/issues/278 if (upgrade == null || !upgrade.toLowerCase().equals(Values.WEBSOCKET.toLowerCase())) { throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + response.headers().get(Names.UPGRADE)); } // Connection header should be matched case-insensitive. // See https://github.com/netty/netty/issues/278 String connection = response.headers().get(Names.CONNECTION); if (connection == null || !connection.toLowerCase().equals(Values.UPGRADE.toLowerCase())) { throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.headers().get(Names.CONNECTION)); } String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT); if (accept == null || !accept.equals(expectedChallengeResponseString)) { throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString)); } String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); setActualSubprotocol(subprotocol); setHandshakeComplete(); channel.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket13FrameDecoder(false, allowExtensions, getMaxFramePayloadLength())); } } WebSocketClientHandshakerFactory.java000066400000000000000000000077561225554127700375770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import java.net.URI; import java.util.Map; import static org.jboss.netty.handler.codec.http.websocketx.WebSocketVersion.*; /** * Instances the appropriate handshake class to use for clients */ public class WebSocketClientHandshakerFactory { /** * Instances a new handshaker * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". * Subsequent web socket frames will be sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. Null if no sub-protocol support is required. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Custom HTTP headers to send during the handshake * @throws WebSocketHandshakeException */ public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders) { return newHandshaker(webSocketURL, version, subprotocol, allowExtensions, customHeaders, Long.MAX_VALUE); } /** * Instances a new handshaker * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". * Subsequent web socket frames will be sent to this URL. * @param version * Version of web socket specification to use to connect to the server * @param subprotocol * Sub protocol request sent to the server. Null if no sub-protocol support is required. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param customHeaders * Custom HTTP headers to send during the handshake * @param maxFramePayloadLength * Maximum allowable frame payload length. Setting this value to your application's * requirement may reduce denial of service attacks using long data frames. * @throws WebSocketHandshakeException */ public WebSocketClientHandshaker newHandshaker( URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, Map customHeaders, long maxFramePayloadLength) { if (version == V13) { return new WebSocketClientHandshaker13( webSocketURL, V13, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength); } if (version == V08) { return new WebSocketClientHandshaker08( webSocketURL, V08, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength); } if (version == V07) { return new WebSocketClientHandshaker07( webSocketURL, V07, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength); } if (version == V00) { return new WebSocketClientHandshaker00( webSocketURL, V00, subprotocol, customHeaders, maxFramePayloadLength); } throw new WebSocketHandshakeException("Protocol version " + version.toString() + " not supported."); } } WebSocketFrame.java000066400000000000000000000037131225554127700340570ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; /** * Base class for web socket frames */ public abstract class WebSocketFrame { /** * Flag to indicate if this frame is the final fragment in a message. The first fragment (frame) may also be the * final fragment. */ private boolean finalFragment = true; /** * RSV1, RSV2, RSV3 used for extensions */ private int rsv; /** * Contents of this frame */ private ChannelBuffer binaryData; /** * Returns binary data */ public ChannelBuffer getBinaryData() { return binaryData; } /** * Sets the binary data for this frame */ public void setBinaryData(ChannelBuffer binaryData) { this.binaryData = binaryData; } /** * Flag to indicate if this frame is the final fragment in a message. The first fragment (frame) may also be the * final fragment. */ public boolean isFinalFragment() { return finalFragment; } public void setFinalFragment(boolean finalFragment) { this.finalFragment = finalFragment; } /** * Bits used for extensions to the standard. */ public int getRsv() { return rsv; } public void setRsv(int rsv) { this.rsv = rsv; } } WebSocketFrameType.java000066400000000000000000000014551225554127700347220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; /** * Type of web socket frames */ public enum WebSocketFrameType { TEXT, BINARY, PING, PONG, CLOSE, CONTINUATION } WebSocketHandshakeException.java000066400000000000000000000020271225554127700365670ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; /** * Exception during handshaking process */ public class WebSocketHandshakeException extends RuntimeException { private static final long serialVersionUID = 1L; public WebSocketHandshakeException(String s) { super(s); } public WebSocketHandshakeException(String s, Throwable throwable) { super(s, throwable); } } WebSocketServerHandshaker.java000066400000000000000000000172361225554127700362710ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.Channels; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.util.internal.StringUtil; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; /** * Base class for server side web socket opening and closing handshakes */ public abstract class WebSocketServerHandshaker { /** * Use this as wildcard to support all requested sub-protocols */ public static final String SUB_PROTOCOL_WILDCARD = "*"; private final String webSocketUrl; private final String[] subprotocols; private final WebSocketVersion version; private final long maxFramePayloadLength; private String selectedSubprotocol; /** * {@link ChannelFutureListener} which will call * {@link Channels#fireExceptionCaught(ChannelHandlerContext, Throwable)} * if the {@link ChannelFuture} was not successful. */ public static final ChannelFutureListener HANDSHAKE_LISTENER = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Channels.fireExceptionCaught(future.getChannel(), future.getCause()); } } }; /** * Constructor using default values * * @param version * the protocol version * @param webSocketUrl * URL for web socket communications. e.g * "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols. Null if sub protocols not * supported. */ protected WebSocketServerHandshaker(WebSocketVersion version, String webSocketUrl, String subprotocols) { this(version, webSocketUrl, subprotocols, Long.MAX_VALUE); } /** * Constructor specifying the destination web socket location * * @param version * the protocol version * @param webSocketUrl * URL for web socket communications. e.g * "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols. Null if sub protocols not * supported. * @param maxFramePayloadLength * Maximum length of a frame's payload */ protected WebSocketServerHandshaker(WebSocketVersion version, String webSocketUrl, String subprotocols, long maxFramePayloadLength) { this.version = version; this.webSocketUrl = webSocketUrl; if (subprotocols != null) { String[] subprotocolArray = StringUtil.split(subprotocols, ','); for (int i = 0; i < subprotocolArray.length; i++) { subprotocolArray[i] = subprotocolArray[i].trim(); } this.subprotocols = subprotocolArray; } else { this.subprotocols = new String[0]; } this.maxFramePayloadLength = maxFramePayloadLength; } /** * Returns the URL of the web socket */ public String getWebSocketUrl() { return webSocketUrl; } /** * Returns the CSV of supported sub protocols */ public Set getSubprotocols() { Set ret = new LinkedHashSet(); Collections.addAll(ret, subprotocols); return ret; } /** * Returns the version of the specification being supported */ public WebSocketVersion getVersion() { return version; } /** * Returns the max length for any frame's payload */ public long getMaxFramePayloadLength() { return maxFramePayloadLength; } /** * Performs the opening handshake * * @param channel * Channel * @param req * HTTP Request */ public abstract ChannelFuture handshake(Channel channel, HttpRequest req); /** * Upgrades the connection and send the handshake response. */ protected ChannelFuture writeHandshakeResponse( Channel channel, HttpResponse res, ChannelHandler encoder, ChannelHandler decoder) { final ChannelPipeline p = channel.getPipeline(); if (p.get(HttpChunkAggregator.class) != null) { p.remove(HttpChunkAggregator.class); } final String httpEncoderName = p.getContext(HttpResponseEncoder.class).getName(); p.addAfter(httpEncoderName, "wsencoder", encoder); p.get(HttpRequestDecoder.class).replace("wsdecoder", decoder); final ChannelFuture future = channel.write(res); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { p.remove(httpEncoderName); } }); return future; } /** * Performs the closing handshake * * @param channel * Channel * @param frame * Closing Frame that was received */ public abstract ChannelFuture close(Channel channel, CloseWebSocketFrame frame); /** * Selects the first matching supported sub protocol * * @param requestedSubprotocols * CSV of protocols to be supported. e.g. "chat, superchat" * @return First matching supported sub protocol. Null if not found. */ protected String selectSubprotocol(String requestedSubprotocols) { if (requestedSubprotocols == null || subprotocols.length == 0) { return null; } String[] requestedSubprotocolArray = StringUtil.split(requestedSubprotocols, ','); for (String p : requestedSubprotocolArray) { String requestedSubprotocol = p.trim(); for (String supportedSubprotocol : subprotocols) { if (SUB_PROTOCOL_WILDCARD.equals(supportedSubprotocol) || requestedSubprotocol.equals(supportedSubprotocol)) { return requestedSubprotocol; } } } // No match found return null; } /** * Returns the selected subprotocol. Null if no subprotocol has been selected. *

* This is only available AFTER handshake() has been called. *

*/ public String getSelectedSubprotocol() { return selectedSubprotocol; } protected void setSelectedSubprotocol(String value) { selectedSubprotocol = value; } } WebSocketServerHandshaker00.java000066400000000000000000000200331225554127700364160ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpHeaders.Values; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** *

* Performs server side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 00 *

*

* A very large portion of this code was taken from the Netty 3.2 HTTP example. *

*/ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker00.class); /** * Constructor with default values * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols */ public WebSocketServerHandshaker00(String webSocketURL, String subprotocols) { this(webSocketURL, subprotocols, Long.MAX_VALUE); } /** * Constructor specifying the destination web socket location * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". * Subsequent web socket frames will be sent to this URL. * @param subprotocols * CSV of supported protocols * @param maxFramePayloadLength * Maximum allowable frame payload length. Setting this value to your application's requirement may * reduce denial of service attacks using long data frames. */ public WebSocketServerHandshaker00(String webSocketURL, String subprotocols, long maxFramePayloadLength) { super(WebSocketVersion.V00, webSocketURL, subprotocols, maxFramePayloadLength); } /** *

* Handle the web socket handshake for the web socket specification HyBi version 0 and lower. This standard * is really a rehash of hixie-76 and * hixie-75. *

* *

* Browser request to the server: *

* *
     * GET /demo HTTP/1.1
     * Upgrade: WebSocket
     * Connection: Upgrade
     * Host: example.com
     * Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, sample
     * Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
     * Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
     *
     * ^n:ds[4U
     * 
* *

* Server response: *

* *
     * HTTP/1.1 101 WebSocket Protocol Handshake
     * Upgrade: WebSocket
     * Connection: Upgrade
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Location: ws://example.com/demo
     * Sec-WebSocket-Protocol: sample
     *
     * 8jKS'y:G*Co,Wxa-
     * 
* * @param channel * Channel * @param req * HTTP request */ @Override public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s WS Version 00 server handshake", channel.getId())); } // Serve the WebSocket handshake request. if (!Values.UPGRADE.equalsIgnoreCase(req.headers().get(CONNECTION)) || !WEBSOCKET.equalsIgnoreCase(req.headers().get(Names.UPGRADE))) { throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade"); } // Hixie 75 does not contain these headers while Hixie 76 does boolean isHixie76 = req.headers().contains(SEC_WEBSOCKET_KEY1) && req.headers().contains(SEC_WEBSOCKET_KEY2); // Create the WebSocket handshake response. HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake")); res.headers().add(Names.UPGRADE, WEBSOCKET); res.headers().add(CONNECTION, Values.UPGRADE); // Fill in the headers and contents depending on handshake method. if (isHixie76) { // New handshake method with a challenge: res.headers().add(SEC_WEBSOCKET_ORIGIN, req.headers().get(ORIGIN)); res.headers().add(SEC_WEBSOCKET_LOCATION, getWebSocketUrl()); String subprotocols = req.headers().get(SEC_WEBSOCKET_PROTOCOL); if (subprotocols != null) { String selectedSubprotocol = selectSubprotocol(subprotocols); if (selectedSubprotocol == null) { throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols); } else { res.headers().add(SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol); setSelectedSubprotocol(selectedSubprotocol); } } // Calculate the answer of the challenge. String key1 = req.headers().get(SEC_WEBSOCKET_KEY1); String key2 = req.headers().get(SEC_WEBSOCKET_KEY2); int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length()); int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length()); long c = req.getContent().readLong(); ChannelBuffer input = ChannelBuffers.buffer(16); input.writeInt(a); input.writeInt(b); input.writeLong(c); res.setContent(WebSocketUtil.md5(input)); } else { // Old Hixie 75 handshake method with no challenge: res.headers().add(WEBSOCKET_ORIGIN, req.headers().get(ORIGIN)); res.headers().add(WEBSOCKET_LOCATION, getWebSocketUrl()); String protocol = req.headers().get(WEBSOCKET_PROTOCOL); if (protocol != null) { res.headers().add(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol)); } } return writeHandshakeResponse( channel, res, new WebSocket00FrameEncoder(), new WebSocket00FrameDecoder(getMaxFramePayloadLength())); } /** * Echo back the closing frame * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { return channel.write(frame); } } WebSocketServerHandshaker07.java000066400000000000000000000144311225554127700364320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** *

* Performs server side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 07 *

*/ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker07.class); public static final String WEBSOCKET_07_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private final boolean allowExtensions; /** * Constructor specifying the destination web socket location * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". * Subsequent web socket frames will be sent to this URL. * @param subprotocols * CSV of supported protocols * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param maxFramePayloadLength * Maximum allowable frame payload length. Setting this value to your application's * requirement may reduce denial of service attacks using long data frames. */ public WebSocketServerHandshaker07( String webSocketURL, String subprotocols, boolean allowExtensions, long maxFramePayloadLength) { super(WebSocketVersion.V07, webSocketURL, subprotocols, maxFramePayloadLength); this.allowExtensions = allowExtensions; } /** *

* Handle the web socket handshake for the web socket specification HyBi version 7. *

* *

* Browser request to the server: *

* *
     * GET /chat HTTP/1.1
     * Host: server.example.com
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, superchat
     * Sec-WebSocket-Version: 7
     * 
* *

* Server response: *

* *
     * HTTP/1.1 101 Switching Protocols
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
     * Sec-WebSocket-Protocol: chat
     * 
* * @param channel * Channel * @param req * HTTP request */ @Override public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s WS Version 7 server handshake", channel.getId())); } HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); String key = req.headers().get(Names.SEC_WEBSOCKET_KEY); if (key == null) { throw new WebSocketHandshakeException("not a WebSocket request: missing key"); } String acceptSeed = key + WEBSOCKET_07_ACCEPT_GUID; ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII)); String accept = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug(String.format("WS Version 7 Server Handshake key: %s. Response: %s.", key, accept)); } res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS); res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase()); res.headers().add(Names.CONNECTION, Names.UPGRADE); res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept); String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); if (subprotocols != null) { String selectedSubprotocol = selectSubprotocol(subprotocols); if (selectedSubprotocol == null) { throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols); } else { res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol); setSelectedSubprotocol(selectedSubprotocol); } } return writeHandshakeResponse( channel, res, new WebSocket07FrameEncoder(false), new WebSocket07FrameDecoder(true, allowExtensions, getMaxFramePayloadLength())); } /** * Echo back the closing frame and close the connection * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { ChannelFuture future = channel.write(frame); future.addListener(ChannelFutureListener.CLOSE); return future; } } WebSocketServerHandshaker08.java000066400000000000000000000156131225554127700364360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** *

* Performs server side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- * 10 *

*/ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker08.class); public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private final boolean allowExtensions; /** * Constructor using defaults * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame */ public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions) { this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE); } /** * Constructor * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param maxFramePayloadLength * Maximum allowable frame payload length. Setting this value to your application's requirement may * reduce denial of service attacks using long data frames. */ public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions, long maxFramePayloadLength) { super(WebSocketVersion.V08, webSocketURL, subprotocols, maxFramePayloadLength); this.allowExtensions = allowExtensions; } /** *

* Handle the web socket handshake for the web socket specification HyBi version 8 to 10. Version 8, 9 and * 10 share the same wire protocol. *

* *

* Browser request to the server: *

* *
     * GET /chat HTTP/1.1
     * Host: server.example.com
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, superchat
     * Sec-WebSocket-Version: 8
     * 
* *

* Server response: *

* *
     * HTTP/1.1 101 Switching Protocols
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
     * Sec-WebSocket-Protocol: chat
     * 
* * @param channel * Channel * @param req * HTTP request */ @Override public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s WS Version 8 server handshake", channel.getId())); } HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); String key = req.headers().get(Names.SEC_WEBSOCKET_KEY); if (key == null) { throw new WebSocketHandshakeException("not a WebSocket request: missing key"); } String acceptSeed = key + WEBSOCKET_08_ACCEPT_GUID; ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII)); String accept = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept)); } res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS); res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase()); res.headers().add(Names.CONNECTION, Names.UPGRADE); res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept); String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); if (subprotocols != null) { String selectedSubprotocol = selectSubprotocol(subprotocols); if (selectedSubprotocol == null) { throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols); } else { res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol); setSelectedSubprotocol(selectedSubprotocol); } } return writeHandshakeResponse( channel, res, new WebSocket08FrameEncoder(false), new WebSocket08FrameDecoder(true, allowExtensions, getMaxFramePayloadLength())); } /** * Echo back the closing frame and close the connection * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { ChannelFuture f = channel.write(frame); f.addListener(ChannelFutureListener.CLOSE); return f; } } WebSocketServerHandshaker13.java000066400000000000000000000161371225554127700364340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.CharsetUtil; import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; /** *

* Performs server side opening and closing handshakes for RFC 6455 (originally web * socket specification version draft-ietf-hybi-thewebsocketprotocol- 17). *

*/ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker13.class); public static final String WEBSOCKET_13_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private final boolean allowExtensions; /** * Constructor using defaults * * @param webSocketURL * URL for web socket communications. e.g * "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols * @param allowExtensions * Allow extensions to be used in the reserved bits of the web * socket frame */ public WebSocketServerHandshaker13(String webSocketURL, String subprotocols, boolean allowExtensions) { this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE); } /** * Constructor specifying the destination web socket location * * @param webSocketURL * URL for web socket communications. e.g * "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param subprotocols * CSV of supported protocols * @param allowExtensions * Allow extensions to be used in the reserved bits of the web * socket frame * @param maxFramePayloadLength * Maximum allowable frame payload length. Setting this value to * your application's requirement may reduce denial of service * attacks using long data frames. */ public WebSocketServerHandshaker13(String webSocketURL, String subprotocols, boolean allowExtensions, long maxFramePayloadLength) { super(WebSocketVersion.V13, webSocketURL, subprotocols, maxFramePayloadLength); this.allowExtensions = allowExtensions; } /** *

* Handle the web socket handshake for the web socket specification HyBi * versions 13-17. Versions 13-17 share the same wire protocol. *

* *

* Browser request to the server: *

* *
     * GET /chat HTTP/1.1
     * Host: server.example.com
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
     * Sec-WebSocket-Origin: http://example.com
     * Sec-WebSocket-Protocol: chat, superchat
     * Sec-WebSocket-Version: 13
     * 
* *

* Server response: *

* *
     * HTTP/1.1 101 Switching Protocols
     * Upgrade: websocket
     * Connection: Upgrade
     * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
     * Sec-WebSocket-Protocol: chat
     * 
* * @param channel * Channel * @param req * HTTP request */ @Override public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s WS Version 13 server handshake", channel.getId())); } HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); String key = req.headers().get(Names.SEC_WEBSOCKET_KEY); if (key == null) { throw new WebSocketHandshakeException("not a WebSocket request: missing key"); } String acceptSeed = key + WEBSOCKET_13_ACCEPT_GUID; ChannelBuffer sha1 = WebSocketUtil.sha1(ChannelBuffers.copiedBuffer(acceptSeed, CharsetUtil.US_ASCII)); String accept = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug(String.format("WS Version 13 Server Handshake key: %s. Response: %s.", key, accept)); } res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS); res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase()); res.headers().add(Names.CONNECTION, Names.UPGRADE); res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept); String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL); if (subprotocols != null) { String selectedSubprotocol = selectSubprotocol(subprotocols); if (selectedSubprotocol == null) { throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols); } else { res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol); setSelectedSubprotocol(selectedSubprotocol); } } return writeHandshakeResponse( channel, res, new WebSocket13FrameEncoder(false), new WebSocket13FrameDecoder(true, allowExtensions, getMaxFramePayloadLength())); } /** * Echo back the closing frame and close the connection * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { ChannelFuture f = channel.write(frame); f.addListener(ChannelFutureListener.CLOSE); return f; } } WebSocketServerHandshakerFactory.java000066400000000000000000000120401225554127700376050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; /** * Instances the appropriate handshake class to use for servers */ public class WebSocketServerHandshakerFactory { private final String webSocketURL; private final String subprotocols; private final boolean allowExtensions; private final long maxFramePayloadLength; /** * Constructor * @param subprotocols * CSV of supported protocols. Null if sub protocols not supported. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame */ public WebSocketServerHandshakerFactory(String webSocketURL, String subprotocols, boolean allowExtensions) { this(webSocketURL, subprotocols, allowExtensions, Long.MAX_VALUE); } /** * Constructor * * @param webSocketURL * URL for web socket communications. e.g "ws://myhost.com/mypath". * Subsequent web socket frames will be sent to this URL. * @param subprotocols * CSV of supported protocols. Null if sub protocols not supported. * @param allowExtensions * Allow extensions to be used in the reserved bits of the web socket frame * @param maxFramePayloadLength * Maximum allowable frame payload length. Setting this value to your application's * requirement may reduce denial of service attacks using long data frames. */ public WebSocketServerHandshakerFactory(String webSocketURL, String subprotocols, boolean allowExtensions, long maxFramePayloadLength) { this.webSocketURL = webSocketURL; this.subprotocols = subprotocols; this.allowExtensions = allowExtensions; this.maxFramePayloadLength = maxFramePayloadLength; } /** * Instances a new handshaker * * @return A new WebSocketServerHandshaker for the requested web socket version. Null if web * socket version is not supported. */ public WebSocketServerHandshaker newHandshaker(HttpRequest req) { String version = req.headers().get(Names.SEC_WEBSOCKET_VERSION); if (version != null) { if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) { // Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification). return new WebSocketServerHandshaker13( webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength); } else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) { // Version 8 of the wire protocol - version 10 of the draft hybi specification. return new WebSocketServerHandshaker08( webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength); } else if (version.equals(WebSocketVersion.V07.toHttpHeaderValue())) { // Version 8 of the wire protocol - version 07 of the draft hybi specification. return new WebSocketServerHandshaker07( webSocketURL, subprotocols, allowExtensions, maxFramePayloadLength); } else { return null; } } else { // Assume version 00 where version header was not specified return new WebSocketServerHandshaker00( webSocketURL, subprotocols, maxFramePayloadLength); } } /** * Return that we need cannot not support the web socket version * * @param channel * Channel */ public ChannelFuture sendUnsupportedWebSocketVersionResponse(Channel channel) { HttpResponse res = new DefaultHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED); res.headers().set(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue()); return channel.write(res); } } WebSocketServerProtocolHandler.java000066400000000000000000000121021225554127700373030ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; /** * Handles WebSocket control frames (Close, Ping, Pong) and data frames (Text and Binary) are passed * to the next handler in the pipeline. */ public class WebSocketServerProtocolHandler extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler { private final String websocketPath; private final String subprotocols; private final boolean allowExtensions; public WebSocketServerProtocolHandler(String websocketPath) { this(websocketPath, null, false); } public WebSocketServerProtocolHandler(String websocketPath, String subprotocols) { this(websocketPath, subprotocols, false); } public WebSocketServerProtocolHandler(String websocketPath, String subprotocols, boolean allowExtensions) { this.websocketPath = websocketPath; this.subprotocols = subprotocols; this.allowExtensions = allowExtensions; } public void afterAdd(ChannelHandlerContext ctx) throws Exception { ChannelPipeline cp = ctx.getPipeline(); if (cp.get(WebSocketServerProtocolHandshakeHandler.class) == null) { // Add the WebSocketHandshakeHandler before this one. ctx.getPipeline().addBefore(ctx.getName(), WebSocketServerProtocolHandshakeHandler.class.getName(), new WebSocketServerProtocolHandshakeHandler(websocketPath, subprotocols, allowExtensions)); } } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) e.getMessage(); if (frame instanceof CloseWebSocketFrame) { WebSocketServerHandshaker handshaker = getHandshaker(ctx); handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); return; } else if (frame instanceof PingWebSocketFrame) { ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); return; } } ctx.sendUpstream(e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (e.getCause() instanceof WebSocketHandshakeException) { DefaultHttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST); response.setContent(ChannelBuffers.wrappedBuffer(e.getCause().getMessage().getBytes())); ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE); } else { ctx.getChannel().close(); } } static WebSocketServerHandshaker getHandshaker(ChannelHandlerContext ctx) { return (WebSocketServerHandshaker) ctx.getAttachment(); } static void setHandshaker(ChannelHandlerContext ctx, WebSocketServerHandshaker handshaker) { ctx.setAttachment(handshaker); } static ChannelHandler forbiddenHttpRequestResponder() { return new SimpleChannelHandler() { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!(e.getMessage() instanceof WebSocketFrame)) { DefaultHttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN); ctx.getChannel().write(response); } else { ctx.sendUpstream(e); } } }; } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { } public void afterRemove(ChannelHandlerContext ctx) throws Exception { } } WebSocketServerProtocolHandshakeHandler.java000066400000000000000000000113251225554127700411200ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive; import static org.jboss.netty.handler.codec.http.HttpMethod.GET; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * Handles the HTTP handshake (the HTTP Upgrade request) */ public class WebSocketServerProtocolHandshakeHandler extends SimpleChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerProtocolHandshakeHandler.class); private final String websocketPath; private final String subprotocols; private final boolean allowExtensions; public WebSocketServerProtocolHandshakeHandler(String websocketPath, String subprotocols, boolean allowExtensions) { this.websocketPath = websocketPath; this.subprotocols = subprotocols; this.allowExtensions = allowExtensions; } @Override public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof HttpRequest) { HttpRequest req = (HttpRequest) e.getMessage(); if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } final WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( getWebSocketLocation(ctx.getPipeline(), req, websocketPath), subprotocols, allowExtensions); final WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); } else { final ChannelFuture handshakeFuture = handshaker.handshake(ctx.getChannel(), req); handshakeFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Channels.fireExceptionCaught(ctx, future.getCause()); } } }); WebSocketServerProtocolHandler.setHandshaker(ctx, handshaker); ctx.getPipeline().replace(this, "WS403Responder", WebSocketServerProtocolHandler.forbiddenHttpRequestResponder()); } } } public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.error("Exception Caught", cause); ctx.getChannel().close(); } private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { ChannelFuture f = ctx.getChannel().write(res); if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) { String protocol = "ws"; if (cp.get(SslHandler.class) != null) { // SSL in use so use Secure WebSockets protocol = "wss"; } return protocol + "://" + req.headers().get(HttpHeaders.Names.HOST) + path; } } WebSocketUtil.java000066400000000000000000000107241225554127700337420ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.base64.Base64; import org.jboss.netty.util.CharsetUtil; /** * TODO Document me. */ final class WebSocketUtil { /** * @deprecated use {@link #md5(ChannelBuffer)} */ @Deprecated static byte[] md5(byte[] bytes) { try { MessageDigest md = MessageDigest.getInstance("MD5"); return md.digest(bytes); } catch (NoSuchAlgorithmException e) { throw new InternalError("MD5 not supported on this platform"); } } /** * Performs an MD5 hash * * @param buffer * buffer to hash * @return Hashed data */ static ChannelBuffer md5(ChannelBuffer buffer) { try { MessageDigest md = MessageDigest.getInstance("MD5"); if (buffer.hasArray()) { int offset = buffer.arrayOffset() + buffer.readerIndex(); int length = buffer.readableBytes(); md.update(buffer.array(), offset, length); } else { md.update(buffer.toByteBuffer()); } return ChannelBuffers.wrappedBuffer(md.digest()); } catch (NoSuchAlgorithmException e) { throw new InternalError("MD5 not supported on this platform"); } } /** * @deprecated use {@link #sha1(ChannelBuffer)} */ @Deprecated static byte[] sha1(byte[] bytes) { try { MessageDigest md = MessageDigest.getInstance("SHA1"); return md.digest(bytes); } catch (NoSuchAlgorithmException e) { throw new InternalError("SHA-1 not supported on this platform"); } } /** * Performs an SHA-1 hash * * @param buffer * buffer to hash * @return Hashed data */ static ChannelBuffer sha1(ChannelBuffer buffer) { try { MessageDigest md = MessageDigest.getInstance("SHA1"); if (buffer.hasArray()) { int offset = buffer.arrayOffset() + buffer.readerIndex(); int length = buffer.readableBytes(); md.update(buffer.array(), offset, length); } else { md.update(buffer.toByteBuffer()); } return ChannelBuffers.wrappedBuffer(md.digest()); } catch (NoSuchAlgorithmException e) { throw new InternalError("SHA-1 not supported on this platform"); } } /** * @deprecated use {@link #base64(ChannelBuffer)} */ @Deprecated static String base64(byte[] bytes) { ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes); return Base64.encode(hashed).toString(CharsetUtil.UTF_8); } /** * Base 64 encoding * * @param buffer * Bytes to encode * @return encoded string */ static String base64(ChannelBuffer buffer) { return Base64.encode(buffer).toString(CharsetUtil.UTF_8); } /** * Creates some random bytes * * @param size * Number of random bytes to create * @return random bytes */ static byte[] randomBytes(int size) { byte[] bytes = new byte[size]; for (int i = 0; i < size; i++) { bytes[i] = (byte) randomNumber(0, 255); } return bytes; } /** * Generates a random number * * @param min * Minimum value * @param max * Maximum value * @return Random number */ static int randomNumber(int min, int max) { return (int) (Math.random() * max + min); } private WebSocketUtil() { // Unused } } WebSocketVersion.java000066400000000000000000000041511225554127700344470ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.websocketx; /** *

* Versions of the web socket specification. *

*

* A specification is tied to one wire protocol version but a protocol version may have use by more than 1 version of * the specification. *

*/ public enum WebSocketVersion { UNKNOWN, /** * draft-ietf-hybi-thewebsocketprotocol- 00. */ V00, /** * draft-ietf-hybi-thewebsocketprotocol- 07 */ V07, /** * draft-ietf-hybi-thewebsocketprotocol- 10 */ V08, /** * RFC 6455. This was originally draft-ietf-hybi-thewebsocketprotocol- * 17 */ V13; /** * @return Value for HTTP Header 'Sec-WebSocket-Version' */ public String toHttpHeaderValue() { if (this == V00) { return "0"; } if (this == V07) { return "7"; } if (this == V08) { return "8"; } if (this == V13) { return "13"; } throw new IllegalStateException("Unknown web socket version: " + this); } } package-info.java000066400000000000000000000034641225554127700335450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder, decoder, handshakers and their related message types for * Web Socket data frames. *

* This package supports different web socket specification versions (hence the X suffix). * The specification current supported are: *

*

*

* For the detailed instruction on adding add Web Socket support to your HTTP * server, take a look into the WebSocketServerX example located in the * {@code org.jboss.netty.example.http.websocket} package. *

* * @apiviz.exclude OneToOne(Encoder|Decoder)$ * @apiviz.exclude \.codec\.replay\. * @apiviz.exclude \.Default */ package org.jboss.netty.handler.codec.http.websocketx; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/000077500000000000000000000000001225554127700275725ustar00rootroot00000000000000ChannelBufferByteInput.java000066400000000000000000000040651225554127700347310ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import java.io.IOException; import org.jboss.marshalling.ByteInput; import org.jboss.netty.buffer.ChannelBuffer; /** * {@link ByteInput} implementation which reads its data from a {@link ChannelBuffer} * * */ class ChannelBufferByteInput implements ByteInput { private final ChannelBuffer buffer; public ChannelBufferByteInput(ChannelBuffer buffer) { this.buffer = buffer; } public void close() throws IOException { // nothing to do } public int available() throws IOException { return buffer.readableBytes(); } public int read() throws IOException { if (buffer.readable()) { return buffer.readByte() & 0xff; } return -1; } public int read(byte[] array) throws IOException { return read(array, 0, array.length); } public int read(byte[] dst, int dstIndex, int length) throws IOException { int available = available(); if (available == 0) { return -1; } length = Math.min(available, length); buffer.readBytes(dst, dstIndex, length); return length; } public long skip(long bytes) throws IOException { int readable = buffer.readableBytes(); if (readable < bytes) { bytes = readable; } buffer.readerIndex((int) (buffer.readerIndex() + bytes)); return bytes; } } ChannelBufferByteOutput.java000066400000000000000000000042371225554127700351330ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import java.io.IOException; import org.jboss.marshalling.ByteOutput; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBuffers; /** * {@link ByteOutput} implementation which writes the data to a {@link ChannelBuffer} * * */ class ChannelBufferByteOutput implements ByteOutput { private final ChannelBuffer buffer; /** * Create a new instance which use the given {@link ChannelBuffer} */ public ChannelBufferByteOutput(ChannelBuffer buffer) { this.buffer = buffer; } /** * Calls {@link #ChannelBufferByteOutput(ChannelBuffer)} with a dynamic {@link ChannelBuffer} */ public ChannelBufferByteOutput(ChannelBufferFactory factory, int estimatedLength) { this(ChannelBuffers.dynamicBuffer(estimatedLength, factory)); } public void close() throws IOException { // Nothing todo } public void flush() throws IOException { // nothing to do } public void write(int b) throws IOException { buffer.writeByte(b); } public void write(byte[] bytes) throws IOException { buffer.writeBytes(bytes); } public void write(byte[] bytes, int srcIndex, int length) throws IOException { buffer.writeBytes(bytes, srcIndex, length); } /** * Return the {@link ChannelBuffer} which contains the written content * */ public ChannelBuffer getBuffer() { return buffer; } } CompatibleMarshallingDecoder.java000066400000000000000000000107711225554127700361130ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.ByteInput; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.handler.codec.replay.VoidEnum; import java.io.ObjectStreamConstants; /** * {@link ReplayingDecoder} which use an {@link Unmarshaller} to read the Object out of the {@link ChannelBuffer}. * * If you can you should use {@link MarshallingDecoder}. * * * */ public class CompatibleMarshallingDecoder extends ReplayingDecoder { protected final UnmarshallerProvider provider; protected final int maxObjectSize; private boolean discardingTooLongFrame; /** * Create a new instance of {@link CompatibleMarshallingDecoder}. * * @param provider * the {@link UnmarshallerProvider} which is used to obtain the {@link Unmarshaller} * for the {@link Channel} * @param maxObjectSize * the maximal size (in bytes) of the {@link Object} to unmarshal. Once the size is * exceeded the {@link Channel} will get closed. Use a a maxObjectSize of * {@link Integer#MAX_VALUE} to disable this. You should only do this if you are sure * that the received Objects will never be big and the sending side are trusted, as * this opens the possibility for a DOS-Attack due an {@link OutOfMemoryError}. */ public CompatibleMarshallingDecoder(UnmarshallerProvider provider, int maxObjectSize) { this.provider = provider; this.maxObjectSize = maxObjectSize; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { if (discardingTooLongFrame) { buffer.skipBytes(actualReadableBytes()); checkpoint(); return null; } Unmarshaller unmarshaller = provider.getUnmarshaller(ctx); ByteInput input = new ChannelBufferByteInput(buffer); if (maxObjectSize != Integer.MAX_VALUE) { input = new LimitingByteInput(input, maxObjectSize); } try { unmarshaller.start(input); Object obj = unmarshaller.readObject(); unmarshaller.finish(); return obj; } catch (LimitingByteInput.TooBigObjectException e) { discardingTooLongFrame = true; throw new TooLongFrameException(); } finally { // Call close in a finally block as the ReplayingDecoder will throw an Error if not enough bytes are // readable. This helps to be sure that we do not leak resource unmarshaller.close(); } } @Override protected Object decodeLast(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { switch (buffer.readableBytes()) { case 0: return null; case 1: // Ignore the last TC_RESET if (buffer.getByte(buffer.readerIndex()) == ObjectStreamConstants.TC_RESET) { buffer.skipBytes(1); return null; } } Object decoded = decode(ctx, channel, buffer, state); return decoded; } /** * Calls {@link Channel#close()} if a TooLongFrameException was thrown */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (e.getCause() instanceof TooLongFrameException) { e.getChannel().close(); } else { super.exceptionCaught(ctx, e); } } } CompatibleMarshallingEncoder.java000066400000000000000000000041451225554127700361230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Marshaller; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * {@link OneToOneEncoder} implementation which uses JBoss Marshalling to marshal * an Object. * * See JBoss Marshalling website * for more informations * * Use {@link MarshallingEncoder} if possible. * */ @Sharable public class CompatibleMarshallingEncoder extends OneToOneEncoder { private final MarshallerProvider provider; /** * Create a new instance of the {@link CompatibleMarshallingEncoder} * * @param provider the {@link MarshallerProvider} to use to get the {@link Marshaller} for a {@link Channel} */ public CompatibleMarshallingEncoder(MarshallerProvider provider) { this.provider = provider; } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { Marshaller marshaller = provider.getMarshaller(ctx); ChannelBufferByteOutput output = new ChannelBufferByteOutput(ctx.getChannel().getConfig().getBufferFactory(), 256); marshaller.start(output); marshaller.writeObject(msg); marshaller.finish(); marshaller.close(); return output.getBuffer(); } } ContextBoundUnmarshallerProvider.java000066400000000000000000000036051225554127700370670ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; /** * {@link UnmarshallerProvider} which store a reference to the {@link Unmarshaller} in the * {@link ChannelHandlerContext} via the {@link ChannelHandlerContext#setAttachment(Object)} * method. So the same {@link Unmarshaller} will be used during the life-time of a {@link Channel} * for the {@link ChannelHandler}'s {@link ChannelHandlerContext}. * * */ public class ContextBoundUnmarshallerProvider extends DefaultUnmarshallerProvider { public ContextBoundUnmarshallerProvider(MarshallerFactory factory, MarshallingConfiguration config) { super(factory, config); } @Override public Unmarshaller getUnmarshaller(ChannelHandlerContext ctx) throws Exception { Unmarshaller unmarshaller = (Unmarshaller) ctx.getAttachment(); if (unmarshaller == null) { unmarshaller = super.getUnmarshaller(ctx); ctx.setAttachment(unmarshaller); } return unmarshaller; } } DefaultMarshallerProvider.java000066400000000000000000000033161225554127700354730ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Marshaller; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.netty.channel.ChannelHandlerContext; /** * Default implementation of {@link MarshallerProvider} which just create a new {@link Marshaller} * on ever {@link #getMarshaller(ChannelHandlerContext)} call. * * */ public class DefaultMarshallerProvider implements MarshallerProvider { private final MarshallerFactory factory; private final MarshallingConfiguration config; /** * Create a new instance * * @param factory the {@link MarshallerFactory} to use to create {@link Marshaller} * @param config the {@link MarshallingConfiguration} */ public DefaultMarshallerProvider(MarshallerFactory factory, MarshallingConfiguration config) { this.factory = factory; this.config = config; } public Marshaller getMarshaller(ChannelHandlerContext ctx) throws Exception { return factory.createMarshaller(config); } } DefaultUnmarshallerProvider.java000066400000000000000000000034161225554127700360370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.channel.ChannelHandlerContext; /** * Default implementation of {@link UnmarshallerProvider} which will just create a new {@link Unmarshaller} * on every call to {@link #getUnmarshaller(ChannelHandlerContext)} * */ public class DefaultUnmarshallerProvider implements UnmarshallerProvider { private final MarshallerFactory factory; private final MarshallingConfiguration config; /** * Create a new instance of {@link DefaultMarshallerProvider} * * @param factory the {@link MarshallerFactory} to use to create {@link Unmarshaller} * @param config the {@link MarshallingConfiguration} */ public DefaultUnmarshallerProvider(MarshallerFactory factory, MarshallingConfiguration config) { this.factory = factory; this.config = config; } public Unmarshaller getUnmarshaller(ChannelHandlerContext ctx) throws Exception { return factory.createUnmarshaller(config); } } LimitingByteInput.java000066400000000000000000000056451225554127700340100ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import java.io.IOException; import org.jboss.marshalling.ByteInput; /** * {@link ByteInput} implementation which wraps another {@link ByteInput} and throws a {@link TooBigObjectException} * if the read limit was reached. * * */ class LimitingByteInput implements ByteInput { // Use a static instance here to remove the overhead of fillStacktrace private static final TooBigObjectException EXCEPTION = new TooBigObjectException(); private final ByteInput input; private final long limit; private long read; public LimitingByteInput(ByteInput input, long limit) { if (limit <= 0) { throw new IllegalArgumentException("The limit MUST be > 0"); } this.input = input; this.limit = limit; } public void close() throws IOException { // Nothing todo } public int available() throws IOException { int available = input.available(); int readable = readable(available); return readable; } public int read() throws IOException { int readable = readable(1); if (readable > 0) { int b = input.read(); read++; return b; } else { throw EXCEPTION; } } public int read(byte[] array) throws IOException { return read(array, 0, array.length); } public int read(byte[] array, int offset, int length) throws IOException { int readable = readable(length); if (readable > 0) { int i = input.read(array, offset, readable); read += i; return i; } else { throw EXCEPTION; } } public long skip(long bytes) throws IOException { int readable = readable((int) bytes); if (readable > 0) { long i = input.skip(readable); read += i; return i; } else { throw EXCEPTION; } } private int readable(int length) { return (int) Math.min(length, limit - read); } /** * Exception that will get thrown if the {@link Object} is to big to unmarshall * */ static final class TooBigObjectException extends IOException { private static final long serialVersionUID = 1L; } } MarshallerProvider.java000066400000000000000000000021251225554127700341630ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Marshaller; import org.jboss.netty.channel.ChannelHandlerContext; /** * This provider is responsible to get a {@link Marshaller} for the given {@link ChannelHandlerContext}. * * */ public interface MarshallerProvider { /** * Get a {@link Marshaller} for the given {@link ChannelHandlerContext} */ Marshaller getMarshaller(ChannelHandlerContext ctx) throws Exception; } MarshallingDecoder.java000066400000000000000000000063501225554127700341110ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import java.io.StreamCorruptedException; import org.jboss.marshalling.ByteInput; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.TooLongFrameException; /** * Decoder which MUST be used with {@link MarshallingEncoder}. * * A {@link LengthFieldBasedFrameDecoder} which use an {@link Unmarshaller} to read the Object out * of the {@link ChannelBuffer}. * */ public class MarshallingDecoder extends LengthFieldBasedFrameDecoder { private final UnmarshallerProvider provider; /** * Creates a new decoder whose maximum object size is {@code 1048576} * bytes. If the size of the received object is greater than * {@code 1048576} bytes, a {@link StreamCorruptedException} will be * raised. * */ public MarshallingDecoder(UnmarshallerProvider provider) { this(provider, 1048576); } /** * Creates a new decoder with the specified maximum object size. * * @param maxObjectSize the maximum byte length of the serialized object. * if the length of the received object is greater * than this value, {@link TooLongFrameException} * will be raised. */ public MarshallingDecoder(UnmarshallerProvider provider, int maxObjectSize) { super(maxObjectSize, 0, 4, 0, 4); this.provider = provider; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { ChannelBuffer frame = (ChannelBuffer) super.decode(ctx, channel, buffer); if (frame == null) { return null; } Unmarshaller unmarshaller = provider.getUnmarshaller(ctx); ByteInput input = new ChannelBufferByteInput(frame); try { unmarshaller.start(input); Object obj = unmarshaller.readObject(); unmarshaller.finish(); return obj; } finally { // Call close in a finally block as the ReplayingDecoder will throw an Error if not // enough bytes are readable. This helps to be sure that we do not leak resource unmarshaller.close(); } } @Override protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length) { return buffer.slice(index, length); } } MarshallingEncoder.java000066400000000000000000000067301225554127700341250ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Marshaller; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * {@link OneToOneEncoder} implementation which uses JBoss Marshalling to marshal * an Object. Be aware that this {@link OneToOneEncoder} is not compatible with * an other client that just use JBoss Marshalling as it includes the size of every * {@link Object} that gets serialized in front of the {@link Object} itself. * * Use this with {@link MarshallingDecoder} * * See JBoss Marshalling website * for more informations * */ @Sharable public class MarshallingEncoder extends OneToOneEncoder { private static final byte[] LENGTH_PLACEHOLDER = new byte[4]; private final MarshallerProvider provider; private final int estimatedLength; /** * Creates a new encoder with the estimated length of 512 bytes. * * @param provider the {@link MarshallerProvider} to use */ public MarshallingEncoder(MarshallerProvider provider) { this(provider, 512); } /** * Creates a new encoder. * * @param provider * the {@link MarshallerProvider} to use * @param estimatedLength * the estimated byte length of the serialized form of an object. * If the length of the serialized form exceeds this value, the * internal buffer will be expanded automatically at the cost of * memory bandwidth. If this value is too big, it will also waste * memory bandwidth. To avoid unnecessary memory copy or allocation * cost, please specify the properly estimated value. */ public MarshallingEncoder(MarshallerProvider provider, int estimatedLength) { if (estimatedLength < 0) { throw new IllegalArgumentException( "estimatedLength: " + estimatedLength); } this.estimatedLength = estimatedLength; this.provider = provider; } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { Marshaller marshaller = provider.getMarshaller(ctx); ChannelBufferByteOutput output = new ChannelBufferByteOutput( ctx.getChannel().getConfig().getBufferFactory(), estimatedLength); output.getBuffer().writeBytes(LENGTH_PLACEHOLDER); marshaller.start(output); marshaller.writeObject(msg); marshaller.finish(); marshaller.close(); ChannelBuffer encoded = output.getBuffer(); encoded.setInt(0, encoded.writerIndex() - 4); return encoded; } } ThreadLocalMarshallerProvider.java000066400000000000000000000042171225554127700362720ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Marshaller; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.netty.channel.ChannelHandlerContext; /** * {@link UnmarshallerProvider} implementation which use a {@link ThreadLocal} to store references * to {@link Marshaller} instances. This may give you some performance boost if you need to marshall * many small {@link Object}'s and your actual Thread count is not to big * * * * */ public class ThreadLocalMarshallerProvider implements MarshallerProvider { private final ThreadLocal marshallers = new ThreadLocal(); private final MarshallerFactory factory; private final MarshallingConfiguration config; /** * Create a new instance of the {@link ThreadLocalMarshallerProvider} * * @param factory the {@link MarshallerFactory} to use to create {@link Marshaller}'s if needed * @param config the {@link MarshallingConfiguration} to use */ public ThreadLocalMarshallerProvider(MarshallerFactory factory, MarshallingConfiguration config) { this.factory = factory; this.config = config; } public Marshaller getMarshaller(ChannelHandlerContext ctx) throws Exception { Marshaller marshaller = marshallers.get(); if (marshaller == null) { marshaller = factory.createMarshaller(config); marshallers.set(marshaller); } return marshaller; } } ThreadLocalUnmarshallerProvider.java000066400000000000000000000042141225554127700366320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.channel.ChannelHandlerContext; /** * {@link UnmarshallerProvider} implementation which use a {@link ThreadLocal} to store references * to {@link Unmarshaller} instances. This may give you some performance boost if you need to unmarshall * many small {@link Object}'s. * * */ public class ThreadLocalUnmarshallerProvider implements UnmarshallerProvider { private final ThreadLocal unmarshallers = new ThreadLocal(); private final MarshallerFactory factory; private final MarshallingConfiguration config; /** * Create a new instance of the {@link ThreadLocalUnmarshallerProvider} * * @param factory the {@link MarshallerFactory} to use to create {@link Unmarshaller}'s if needed * @param config the {@link MarshallingConfiguration} to use */ public ThreadLocalUnmarshallerProvider(MarshallerFactory factory, MarshallingConfiguration config) { this.factory = factory; this.config = config; } public Unmarshaller getUnmarshaller(ChannelHandlerContext ctx) throws Exception { Unmarshaller unmarshaller = unmarshallers.get(); if (unmarshaller == null) { unmarshaller = factory.createUnmarshaller(config); unmarshallers.set(unmarshaller); } return unmarshaller; } } UnmarshallerProvider.java000066400000000000000000000021301225554127700345220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.channel.ChannelHandlerContext; /** * This provider is responsible to get an {@link Unmarshaller} for a {@link ChannelHandlerContext} * */ public interface UnmarshallerProvider { /** * Get the {@link Unmarshaller} for the given {@link ChannelHandlerContext} */ Unmarshaller getUnmarshaller(ChannelHandlerContext ctx) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/marshalling/package-info.java000066400000000000000000000014431225554127700327630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Decoder and Encoder which uses JBoss Marshalling. * */ package org.jboss.netty.handler.codec.marshalling; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/oneone/000077500000000000000000000000001225554127700265545ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/oneone/OneToOneDecoder.java000066400000000000000000000060311225554127700323730ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.oneone; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.frame.FrameDecoder; /** * Transforms a received message into another message. Please note that this * decoder must be used with a proper {@link FrameDecoder} such as * {@link DelimiterBasedFrameDecoder} or you must implement proper framing * mechanism by yourself if you are using a stream-based transport such as * TCP/IP. A typical setup for TCP/IP would be: *
 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder", new {@link DelimiterBasedFrameDecoder}(80, {@link Delimiters#nulDelimiter()}));
 * pipeline.addLast("customDecoder", new {@link OneToOneDecoder}() { ... });
 *
 * // Encoder
 * pipeline.addLast("customEncoder", new {@link OneToOneEncoder}() { ... });
 * 
* * @apiviz.landmark */ public abstract class OneToOneDecoder implements ChannelUpstreamHandler { /** * Creates a new instance with the current system character set. */ protected OneToOneDecoder() { } public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (!(evt instanceof MessageEvent)) { ctx.sendUpstream(evt); return; } MessageEvent e = (MessageEvent) evt; Object originalMessage = e.getMessage(); Object decodedMessage = decode(ctx, e.getChannel(), originalMessage); if (originalMessage == decodedMessage) { ctx.sendUpstream(evt); } else if (decodedMessage != null) { fireMessageReceived(ctx, decodedMessage, e.getRemoteAddress()); } } /** * Transforms the specified received message into another message and return * the transformed message. Return {@code null} if the received message * is supposed to be discarded. */ protected abstract Object decode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/oneone/OneToOneEncoder.java000066400000000000000000000060211225554127700324040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.oneone; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import static org.jboss.netty.channel.Channels.*; /** * Transforms a write request into another write request. A typical setup for * TCP/IP would be: *
 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder", new {@link DelimiterBasedFrameDecoder}(80, {@link Delimiters#nulDelimiter()}));
 * pipeline.addLast("customDecoder", new {@link OneToOneDecoder}() { ... });
 *
 * // Encoder
 * pipeline.addLast("customEncoder", new {@link OneToOneEncoder}() { ... });
 * 
* * @apiviz.landmark */ public abstract class OneToOneEncoder implements ChannelDownstreamHandler { protected OneToOneEncoder() { } public void handleDownstream( ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (!(evt instanceof MessageEvent)) { ctx.sendDownstream(evt); return; } MessageEvent e = (MessageEvent) evt; if (!doEncode(ctx, e)) { ctx.sendDownstream(e); } } protected boolean doEncode(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object originalMessage = e.getMessage(); Object encodedMessage = encode(ctx, e.getChannel(), originalMessage); if (originalMessage == encodedMessage) { return false; } if (encodedMessage != null) { write(ctx, e.getFuture(), encodedMessage, e.getRemoteAddress()); } return true; } /** * Transforms the specified message into another message and return the * transformed message. Note that you can not return {@code null}, unlike * you can in {@link OneToOneDecoder#decode(ChannelHandlerContext, Channel, Object)}; * you must return something, at least {@link ChannelBuffers#EMPTY_BUFFER}. */ protected abstract Object encode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception; } OneToOneStrictEncoder.java000066400000000000000000000027031225554127700335210ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/oneone/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.oneone; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; /** * Special {@link OneToOneEncoder} which enforce strict ordering of encoding and writing. This * class should get extend by implementations that needs this enforcement to guaranteer no corruption. * Basically all "message" based {@link OneToOneEncoder} mostly don't need this, where "stream" based * are often in need of it. * */ public abstract class OneToOneStrictEncoder extends OneToOneEncoder { @Override protected boolean doEncode(ChannelHandlerContext ctx, MessageEvent e) throws Exception { // Synchronize on the channel to guaranteer the strict ordering synchronized (ctx.getChannel()) { return super.doEncode(ctx, e); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/oneone/package-info.java000066400000000000000000000015571225554127700317530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Simplistic abstract classes which help implement encoder and decoder that * transform an object into another object and vice versa. * * @apiviz.exclude \.codec\.(?!oneone)[a-z0-9]+\. */ package org.jboss.netty.handler.codec.oneone; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/package-info.java000066400000000000000000000013111225554127700304540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Base package for codecs * */ package org.jboss.netty.handler.codec; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/protobuf/000077500000000000000000000000001225554127700271315ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufDecoder.java000066400000000000000000000115541225554127700330700ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import com.google.protobuf.MessageLite; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; /** * Decodes a received {@link ChannelBuffer} into a * Google Protocol Buffers * {@link Message} and {@link MessageLite}. Please note that this decoder must * be used with a proper {@link FrameDecoder} such as {@link ProtobufVarint32FrameDecoder} * or {@link LengthFieldBasedFrameDecoder} if you are using a stream-based * transport such as TCP/IP. A typical setup for TCP/IP would be: *
 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder",
 *                  new {@link LengthFieldBasedFrameDecoder}(1048576, 0, 4, 0, 4));
 * pipeline.addLast("protobufDecoder",
 *                  new {@link ProtobufDecoder}(MyMessage.getDefaultInstance()));
 *
 * // Encoder
 * pipeline.addLast("frameEncoder", new {@link LengthFieldPrepender}(4));
 * pipeline.addLast("protobufEncoder", new {@link ProtobufEncoder}());
 * 
* and then you can use a {@code MyMessage} instead of a {@link ChannelBuffer} * as a message: *
 * void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     MyMessage req = (MyMessage) e.getMessage();
 *     MyMessage res = MyMessage.newBuilder().setText(
 *                               "Did you say '" + req.getText() + "'?").build();
 *     ch.write(res);
 * }
 * 
* * @apiviz.landmark */ @Sharable public class ProtobufDecoder extends OneToOneDecoder { private static final boolean HAS_PARSER; static { boolean hasParser = false; try { // MessageLite.getParsetForType() is not available until protobuf 2.5.0. MessageLite.class.getDeclaredMethod("getParserForType"); hasParser = true; } catch (Throwable t) { // Ignore } HAS_PARSER = hasParser; } private final MessageLite prototype; private final ExtensionRegistry extensionRegistry; /** * Creates a new instance. */ public ProtobufDecoder(MessageLite prototype) { this(prototype, null); } public ProtobufDecoder(MessageLite prototype, ExtensionRegistry extensionRegistry) { if (prototype == null) { throw new NullPointerException("prototype"); } this.prototype = prototype.getDefaultInstanceForType(); this.extensionRegistry = extensionRegistry; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer)) { return msg; } ChannelBuffer buf = (ChannelBuffer) msg; final byte[] array; final int offset; final int length = buf.readableBytes(); if (buf.hasArray()) { array = buf.array(); offset = buf.arrayOffset() + buf.readerIndex(); } else { array = new byte[length]; buf.getBytes(buf.readerIndex(), array, 0, length); offset = 0; } if (extensionRegistry == null) { if (HAS_PARSER) { return prototype.getParserForType().parseFrom(array, offset, length); } else { return prototype.newBuilderForType().mergeFrom(array, offset, length).build(); } } else { if (HAS_PARSER) { return prototype.getParserForType().parseFrom(array, offset, length, extensionRegistry); } else { return prototype.newBuilderForType().mergeFrom(array, offset, length, extensionRegistry).build(); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufEncoder.java000066400000000000000000000057751225554127700331120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import com.google.protobuf.Message; import com.google.protobuf.MessageLite; /** * Encodes the requested Google * Protocol Buffers {@link Message} and {@link MessageLite} into a * {@link ChannelBuffer}. A typical setup for TCP/IP would be: *
 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder",
 *                  new {@link LengthFieldBasedFrameDecoder}(1048576, 0, 4, 0, 4));
 * pipeline.addLast("protobufDecoder",
 *                  new {@link ProtobufDecoder}(MyMessage.getDefaultInstance()));
 *
 * // Encoder
 * pipeline.addLast("frameEncoder", new {@link LengthFieldPrepender}(4));
 * pipeline.addLast("protobufEncoder", new {@link ProtobufEncoder}());
 * 
* and then you can use a {@code MyMessage} instead of a {@link ChannelBuffer} * as a message: *
 * void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     MyMessage req = (MyMessage) e.getMessage();
 *     MyMessage res = MyMessage.newBuilder().setText(
 *                               "Did you say '" + req.getText() + "'?").build();
 *     ch.write(res);
 * }
 * 
* * @apiviz.landmark */ @Sharable public class ProtobufEncoder extends OneToOneEncoder { @Override protected Object encode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof MessageLite) { byte[] array = ((MessageLite) msg).toByteArray(); return ctx.getChannel().getConfig().getBufferFactory().getBuffer(array, 0, array.length); } if (msg instanceof MessageLite.Builder) { byte[] array = ((MessageLite.Builder) msg).build().toByteArray(); return ctx.getChannel().getConfig().getBufferFactory().getBuffer(array, 0, array.length); } return msg; } } ProtobufVarint32FrameDecoder.java000066400000000000000000000054311225554127700353120ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/protobuf/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.CorruptedFrameException; import org.jboss.netty.handler.codec.frame.FrameDecoder; import com.google.protobuf.CodedInputStream; /** * A decoder that splits the received {@link ChannelBuffer}s dynamically by the * value of the Google Protocol Buffers * Base * 128 Varints integer length field in the message. For example: *
 * BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)
 * +--------+---------------+      +---------------+
 * | Length | Protobuf Data |----->| Protobuf Data |
 * | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |
 * +--------+---------------+      +---------------+
 * 
* * @see CodedInputStream */ public class ProtobufVarint32FrameDecoder extends FrameDecoder { // TODO maxFrameLength + safe skip + fail-fast option // (just like LengthFieldBasedFrameDecoder) @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { buffer.markReaderIndex(); final byte[] buf = new byte[5]; for (int i = 0; i < buf.length; i ++) { if (!buffer.readable()) { buffer.resetReaderIndex(); return null; } buf[i] = buffer.readByte(); if (buf[i] >= 0) { int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); if (length < 0) { throw new CorruptedFrameException("negative length: " + length); } if (buffer.readableBytes() < length) { buffer.resetReaderIndex(); return null; } else { return buffer.readBytes(length); } } } // Couldn't find the byte whose MSB is off. throw new CorruptedFrameException("length wider than 32-bit"); } } ProtobufVarint32LengthFieldPrepender.java000066400000000000000000000047451225554127700370330ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/protobuf/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import static org.jboss.netty.buffer.ChannelBuffers.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import com.google.protobuf.CodedOutputStream; /** * An encoder that prepends the the Google Protocol Buffers * Base * 128 Varints integer length field. For example: *
 * BEFORE DECODE (300 bytes)       AFTER DECODE (302 bytes)
 * +---------------+               +--------+---------------+
 * | Protobuf Data |-------------->| Length | Protobuf Data |
 * |  (300 bytes)  |               | 0xAC02 |  (300 bytes)  |
 * +---------------+               +--------+---------------+
 * 
* * * @see CodedOutputStream */ @Sharable public class ProtobufVarint32LengthFieldPrepender extends OneToOneEncoder { @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer)) { return msg; } ChannelBuffer body = (ChannelBuffer) msg; int length = body.readableBytes(); ChannelBuffer header = channel.getConfig().getBufferFactory().getBuffer( body.order(), CodedOutputStream.computeRawVarint32Size(length)); CodedOutputStream codedOutputStream = CodedOutputStream .newInstance(new ChannelBufferOutputStream(header)); codedOutputStream.writeRawVarint32(length); codedOutputStream.flush(); return wrappedBuffer(header, body); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/protobuf/package-info.java000066400000000000000000000017251225554127700323250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder and decoder which transform a * Google Protocol Buffers * {@link com.google.protobuf.Message} into a {@link org.jboss.netty.buffer.ChannelBuffer} * and vice versa. * * @apiviz.exclude \.oneone\. * @apiviz.exclude \.frame\. */ package org.jboss.netty.handler.codec.protobuf; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/000077500000000000000000000000001225554127700265655ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/ReplayError.java000066400000000000000000000014301225554127700316740ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; class ReplayError extends Error { private static final long serialVersionUID = 2666698631187527681L; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/ReplayingDecoder.java000066400000000000000000000521741225554127700326610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.FrameDecoder; import java.net.SocketAddress; /** * A specialized variation of {@link FrameDecoder} which enables implementation * of a non-blocking decoder in the blocking I/O paradigm. *

* The biggest difference between {@link ReplayingDecoder} and * {@link FrameDecoder} is that {@link ReplayingDecoder} allows you to * implement the {@code decode()} and {@code decodeLast()} methods just like * all required bytes were received already, rather than checking the * availability of the required bytes. For example, the following * {@link FrameDecoder} implementation: *

 * public class IntegerHeaderFrameDecoder extends {@link FrameDecoder} {
 *
 *   {@code @Override}
 *   protected Object decode({@link ChannelHandlerContext} ctx,
 *                           {@link Channel} channel,
 *                           {@link ChannelBuffer} buf) throws Exception {
 *
 *     if (buf.readableBytes() < 4) {
 *        return null;
 *     }
 *
 *     buf.markReaderIndex();
 *     int length = buf.readInt();
 *
 *     if (buf.readableBytes() < length) {
 *        buf.resetReaderIndex();
 *        return null;
 *     }
 *
 *     return buf.readBytes(length);
 *   }
 * }
 * 
* is simplified like the following with {@link ReplayingDecoder}: *
 * public class IntegerHeaderFrameDecoder
 *      extends {@link ReplayingDecoder}<{@link VoidEnum}> {
 *
 *   protected Object decode({@link ChannelHandlerContext} ctx,
 *                           {@link Channel} channel,
 *                           {@link ChannelBuffer} buf,
 *                           {@link VoidEnum} state) throws Exception {
 *
 *     return buf.readBytes(buf.readInt());
 *   }
 * }
 * 
* *

How does this work?

*

* {@link ReplayingDecoder} passes a specialized {@link ChannelBuffer} * implementation which throws an {@link Error} of certain type when there's not * enough data in the buffer. In the {@code IntegerHeaderFrameDecoder} above, * you just assumed that there will be 4 or more bytes in the buffer when * you call {@code buf.readInt()}. If there's really 4 bytes in the buffer, * it will return the integer header as you expected. Otherwise, the * {@link Error} will be raised and the control will be returned to * {@link ReplayingDecoder}. If {@link ReplayingDecoder} catches the * {@link Error}, then it will rewind the {@code readerIndex} of the buffer * back to the 'initial' position (i.e. the beginning of the buffer) and call * the {@code decode(..)} method again when more data is received into the * buffer. *

* Please note that {@link ReplayingDecoder} always throws the same cached * {@link Error} instance to avoid the overhead of creating a new {@link Error} * and filling its stack trace for every throw. * *

Limitations

*

* At the cost of the simplicity, {@link ReplayingDecoder} enforces you a few * limitations: *

    *
  • Some buffer operations are prohibited.
  • *
  • Performance can be worse if the network is slow and the message * format is complicated unlike the example above. In this case, your * decoder might have to decode the same part of the message over and over * again.
  • *
  • You must keep in mind that {@code decode(..)} method can be called many * times to decode a single message. For example, the following code will * not work: *
     public class MyDecoder extends {@link ReplayingDecoder}<{@link VoidEnum}> {
     *
     *   private final Queue<Integer> values = new LinkedList<Integer>();
     *
     *   {@code @Override}
     *   public Object decode(.., {@link ChannelBuffer} buffer, ..) throws Exception {
     *
     *     // A message contains 2 integers.
     *     values.offer(buffer.readInt());
     *     values.offer(buffer.readInt());
     *
     *     // This assertion will fail intermittently since values.offer()
     *     // can be called more than two times!
     *     assert values.size() == 2;
     *     return values.poll() + values.poll();
     *   }
     * }
    * The correct implementation looks like the following, and you can also * utilize the 'checkpoint' feature which is explained in detail in the * next section. *
     public class MyDecoder extends {@link ReplayingDecoder}<{@link VoidEnum}> {
     *
     *   private final Queue<Integer> values = new LinkedList<Integer>();
     *
     *   {@code @Override}
     *   public Object decode(.., {@link ChannelBuffer} buffer, ..) throws Exception {
     *
     *     // Revert the state of the variable that might have been changed
     *     // since the last partial decode.
     *     values.clear();
     *
     *     // A message contains 2 integers.
     *     values.offer(buffer.readInt());
     *     values.offer(buffer.readInt());
     *
     *     // Now we know this assertion will never fail.
     *     assert values.size() == 2;
     *     return values.poll() + values.poll();
     *   }
     * }
    *
  • *
* *

Improving the performance

*

* Fortunately, the performance of a complex decoder implementation can be * improved significantly with the {@code checkpoint()} method. The * {@code checkpoint()} method updates the 'initial' position of the buffer so * that {@link ReplayingDecoder} rewinds the {@code readerIndex} of the buffer * to the last position where you called the {@code checkpoint()} method. * *

Calling {@code checkpoint(T)} with an {@link Enum}

*

* Although you can just use {@code checkpoint()} method and manage the state * of the decoder by yourself, the easiest way to manage the state of the * decoder is to create an {@link Enum} type which represents the current state * of the decoder and to call {@code checkpoint(T)} method whenever the state * changes. You can have as many states as you want depending on the * complexity of the message you want to decode: * *

 * public enum MyDecoderState {
 *   READ_LENGTH,
 *   READ_CONTENT;
 * }
 *
 * public class IntegerHeaderFrameDecoder
 *      extends {@link ReplayingDecoder}<MyDecoderState> {
 *
 *   private int length;
 *
 *   public IntegerHeaderFrameDecoder() {
 *     // Set the initial state.
 *     super(MyDecoderState.READ_LENGTH);
 *   }
 *
 *   {@code @Override}
 *   protected Object decode({@link ChannelHandlerContext} ctx,
 *                           {@link Channel} channel,
 *                           {@link ChannelBuffer} buf,
 *                           MyDecoderState state) throws Exception {
 *     switch (state) {
 *     case READ_LENGTH:
 *       length = buf.readInt();
 *       checkpoint(MyDecoderState.READ_CONTENT);
 *     case READ_CONTENT:
 *       ChannelBuffer frame = buf.readBytes(length);
 *       checkpoint(MyDecoderState.READ_LENGTH);
 *       return frame;
 *     default:
 *       throw new Error("Shouldn't reach here.");
 *     }
 *   }
 * }
 * 
* *

Calling {@code checkpoint()} with no parameter

*

* An alternative way to manage the decoder state is to manage it by yourself. *

 * public class IntegerHeaderFrameDecoder
 *      extends {@link ReplayingDecoder}<{@link VoidEnum}> {
 *
 *   private boolean readLength;
 *   private int length;
 *
 *   {@code @Override}
 *   protected Object decode({@link ChannelHandlerContext} ctx,
 *                           {@link Channel} channel,
 *                           {@link ChannelBuffer} buf,
 *                           {@link VoidEnum} state) throws Exception {
 *     if (!readLength) {
 *       length = buf.readInt();
 *       readLength = true;
 *       checkpoint();
 *     }
 *
 *     if (readLength) {
 *       ChannelBuffer frame = buf.readBytes(length);
 *       readLength = false;
 *       checkpoint();
 *       return frame;
 *     }
 *   }
 * }
 * 
* *

Replacing a decoder with another decoder in a pipeline

*

* If you are going to write a protocol multiplexer, you will probably want to * replace a {@link ReplayingDecoder} (protocol detector) with another * {@link ReplayingDecoder} or {@link FrameDecoder} (actual protocol decoder). * It is not possible to achieve this simply by calling * {@link ChannelPipeline#replace(ChannelHandler, String, ChannelHandler)}, but * some additional steps are required: *

 * public class FirstDecoder extends {@link ReplayingDecoder}<{@link VoidEnum}> {
 *
 *     public FirstDecoder() {
 *         super(true); // Enable unfold
 *     }
 *
 *     {@code @Override}
 *     protected Object decode({@link ChannelHandlerContext} ctx,
 *                             {@link Channel} ch,
 *                             {@link ChannelBuffer} buf,
 *                             {@link VoidEnum} state) {
 *         ...
 *         // Decode the first message
 *         Object firstMessage = ...;
 *
 *         // Add the second decoder
 *         ctx.getPipeline().addLast("second", new SecondDecoder());
 *
 *         // Remove the first decoder (me)
 *         ctx.getPipeline().remove(this);
 *
 *         if (buf.readable()) {
 *             // Hand off the remaining data to the second decoder
 *             return new Object[] { firstMessage, buf.readBytes(super.actualReadableBytes()) };
 *         } else {
 *             // Nothing to hand off
 *             return firstMessage;
 *         }
 *     }
 * 
* * @param * the state type; use {@link VoidEnum} if state management is unused * * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.replay.UnreplayableOperationException oneway - - throws */ public abstract class ReplayingDecoder> extends FrameDecoder { private final ReplayingDecoderBuffer replayable = new ReplayingDecoderBuffer(this); private T state; private int checkpoint; private boolean needsCleanup; /** * Creates a new instance with no initial state (i.e: {@code null}). */ protected ReplayingDecoder() { this(null); } protected ReplayingDecoder(boolean unfold) { this(null, unfold); } /** * Creates a new instance with the specified initial state. */ protected ReplayingDecoder(T initialState) { this(initialState, false); } protected ReplayingDecoder(T initialState, boolean unfold) { super(unfold); state = initialState; } @Override protected ChannelBuffer internalBuffer() { return super.internalBuffer(); } /** * Stores the internal cumulative buffer's reader position. */ protected void checkpoint() { ChannelBuffer cumulation = this.cumulation; if (cumulation != null) { checkpoint = cumulation.readerIndex(); } else { checkpoint = -1; // buffer not available (already cleaned up) } } /** * Stores the internal cumulative buffer's reader position and updates * the current decoder state. */ protected void checkpoint(T state) { checkpoint(); setState(state); } /** * Returns the current state of this decoder. * @return the current state of this decoder */ protected T getState() { return state; } /** * Sets the current state of this decoder. * @return the old state of this decoder */ protected T setState(T newState) { T oldState = state; state = newState; return oldState; } /** * Decodes the received packets so far into a frame. * * @param ctx the context of this handler * @param channel the current channel * @param buffer the cumulative buffer of received packets so far. * Note that the buffer might be empty, which means you * should not make an assumption that the buffer contains * at least one byte in your decoder implementation. * @param state the current decoder state ({@code null} if unused) * * @return the decoded frame */ protected abstract Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, T state) throws Exception; /** * Decodes the received data so far into a frame when the channel is * disconnected. * * @param ctx the context of this handler * @param channel the current channel * @param buffer the cumulative buffer of received packets so far. * Note that the buffer might be empty, which means you * should not make an assumption that the buffer contains * at least one byte in your decoder implementation. * @param state the current decoder state ({@code null} if unused) * * @return the decoded frame */ protected Object decodeLast( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, T state) throws Exception { return decode(ctx, channel, buffer, state); } /** * Calls {@link #decode(ChannelHandlerContext, Channel, ChannelBuffer, Enum)}. This method * should be never used by {@link ReplayingDecoder} itself. But to be safe we should handle it * anyway */ @Override protected final Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { return decode(ctx, channel, buffer, state); } @Override protected final Object decodeLast( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { return decodeLast(ctx, channel, buffer, state); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object m = e.getMessage(); if (!(m instanceof ChannelBuffer)) { ctx.sendUpstream(e); return; } ChannelBuffer input = (ChannelBuffer) m; if (!input.readable()) { return; } needsCleanup = true; if (cumulation == null) { // the cumulation buffer is not created yet so just pass the input // to callDecode(...) method cumulation = input; int oldReaderIndex = input.readerIndex(); int inputSize = input.readableBytes(); try { callDecode( ctx, e.getChannel(), input, replayable, e.getRemoteAddress()); } finally { int readableBytes = input.readableBytes(); if (readableBytes > 0) { int inputCapacity = input.capacity(); // check if readableBytes == capacity we can safe the copy as we will not be able to // optimize memory usage anyway boolean copy = readableBytes != inputCapacity && inputCapacity > getMaxCumulationBufferCapacity(); // seems like there is something readable left in the input buffer // or decoder wants a replay - create the cumulation buffer and // copy the input into it ChannelBuffer cumulation; if (checkpoint > 0) { int bytesToPreserve = inputSize - (checkpoint - oldReaderIndex); if (copy) { this.cumulation = cumulation = newCumulationBuffer(ctx, bytesToPreserve); cumulation.writeBytes(input, checkpoint, bytesToPreserve); } else { this.cumulation = input.slice(checkpoint, bytesToPreserve); } } else if (checkpoint == 0) { if (copy) { this.cumulation = cumulation = newCumulationBuffer(ctx, inputSize); cumulation.writeBytes(input, oldReaderIndex, inputSize); cumulation.readerIndex(input.readerIndex()); } else { this.cumulation = cumulation = input.slice(oldReaderIndex, inputSize); cumulation.readerIndex(input.readerIndex()); } } else { if (copy) { this.cumulation = cumulation = newCumulationBuffer(ctx, input.readableBytes()); cumulation.writeBytes(input); } else { this.cumulation = input; } } } else { cumulation = null; } } } else { input = appendToCumulation(input); try { callDecode(ctx, e.getChannel(), input, replayable, e.getRemoteAddress()); } finally { updateCumulation(ctx, input); } } } private void callDecode( ChannelHandlerContext context, Channel channel, ChannelBuffer input, ChannelBuffer replayableInput, SocketAddress remoteAddress) throws Exception { while (input.readable()) { int oldReaderIndex = checkpoint = input.readerIndex(); Object result = null; T oldState = state; try { result = decode(context, channel, replayableInput, state); if (result == null) { if (oldReaderIndex == input.readerIndex() && oldState == state) { throw new IllegalStateException( "null cannot be returned if no data is consumed and state didn't change."); } else { // Previous data has been discarded or caused state transition. // Probably it is reading on. continue; } } } catch (ReplayError replay) { // Return to the checkpoint (or oldPosition) and retry. int checkpoint = this.checkpoint; if (checkpoint >= 0) { input.readerIndex(checkpoint); } else { // Called by cleanup() - no need to maintain the readerIndex // anymore because the buffer has been released already. } } if (result == null) { // Seems like more data is required. // Let us wait for the next notification. break; } if (oldReaderIndex == input.readerIndex() && oldState == state) { throw new IllegalStateException( "decode() method must consume at least one byte " + "if it returned a decoded message (caused by: " + getClass() + ')'); } // A successful decode unfoldAndFireMessageReceived(context, remoteAddress, result); } } @Override protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { try { ChannelBuffer cumulation = this.cumulation; if (!needsCleanup) { return; } needsCleanup = false; replayable.terminate(); if (cumulation != null && cumulation.readable()) { // Make sure all data was read before notifying a closed channel. callDecode(ctx, e.getChannel(), cumulation, replayable, null); } // Call decodeLast() finally. Please note that decodeLast() is // called even if there's nothing more to read from the buffer to // notify a user that the connection was closed explicitly. Object partiallyDecoded = decodeLast(ctx, e.getChannel(), replayable, state); this.cumulation = null; if (partiallyDecoded != null) { unfoldAndFireMessageReceived(ctx, null, partiallyDecoded); } } catch (ReplayError replay) { // Ignore } finally { ctx.sendUpstream(e); } } } ReplayingDecoderBuffer.java000066400000000000000000000445111225554127700337300ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.charset.Charset; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBufferIndexFinder; class ReplayingDecoderBuffer implements ChannelBuffer { private static final Error REPLAY = new ReplayError(); private final ReplayingDecoder parent; private boolean terminated; ReplayingDecoderBuffer(ReplayingDecoder parent) { this.parent = parent; } private ChannelBuffer buf() { return parent.internalBuffer(); } void terminate() { terminated = true; } public int capacity() { if (terminated) { return buf().capacity(); } else { return Integer.MAX_VALUE; } } public boolean isDirect() { return buf().isDirect(); } public boolean hasArray() { return false; } public byte[] array() { throw new UnsupportedOperationException(); } public int arrayOffset() { throw new UnsupportedOperationException(); } public void clear() { throw new UnreplayableOperationException(); } @Override public boolean equals(Object obj) { return this == obj; } public int compareTo(ChannelBuffer buffer) { throw new UnreplayableOperationException(); } public ChannelBuffer copy() { throw new UnreplayableOperationException(); } public ChannelBuffer copy(int index, int length) { checkIndex(index, length); return buf().copy(index, length); } public void discardReadBytes() { throw new UnreplayableOperationException(); } public void ensureWritableBytes(int writableBytes) { throw new UnreplayableOperationException(); } public ChannelBuffer duplicate() { throw new UnreplayableOperationException(); } public byte getByte(int index) { checkIndex(index, 1); return buf().getByte(index); } public short getUnsignedByte(int index) { checkIndex(index, 1); return buf().getUnsignedByte(index); } public void getBytes(int index, byte[] dst, int dstIndex, int length) { checkIndex(index, length); buf().getBytes(index, dst, dstIndex, length); } public void getBytes(int index, byte[] dst) { checkIndex(index, dst.length); buf().getBytes(index, dst); } public void getBytes(int index, ByteBuffer dst) { throw new UnreplayableOperationException(); } public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) { checkIndex(index, length); buf().getBytes(index, dst, dstIndex, length); } public void getBytes(int index, ChannelBuffer dst, int length) { throw new UnreplayableOperationException(); } public void getBytes(int index, ChannelBuffer dst) { throw new UnreplayableOperationException(); } public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { throw new UnreplayableOperationException(); } public void getBytes(int index, OutputStream out, int length) throws IOException { throw new UnreplayableOperationException(); } public int getInt(int index) { checkIndex(index, 4); return buf().getInt(index); } public long getUnsignedInt(int index) { checkIndex(index, 4); return buf().getUnsignedInt(index); } public long getLong(int index) { checkIndex(index, 8); return buf().getLong(index); } public int getMedium(int index) { checkIndex(index, 3); return buf().getMedium(index); } public int getUnsignedMedium(int index) { checkIndex(index, 3); return buf().getUnsignedMedium(index); } public short getShort(int index) { checkIndex(index, 2); return buf().getShort(index); } public int getUnsignedShort(int index) { checkIndex(index, 2); return buf().getUnsignedShort(index); } public char getChar(int index) { checkIndex(index, 2); return buf().getChar(index); } public float getFloat(int index) { checkIndex(index, 4); return buf().getFloat(index); } public double getDouble(int index) { checkIndex(index, 8); return buf().getDouble(index); } @Override public int hashCode() { throw new UnreplayableOperationException(); } public int indexOf(int fromIndex, int toIndex, byte value) { int endIndex = buf().indexOf(fromIndex, toIndex, value); if (endIndex < 0) { throw REPLAY; } return endIndex; } public int indexOf(int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) { int endIndex = buf().indexOf(fromIndex, toIndex, indexFinder); if (endIndex < 0) { throw REPLAY; } return endIndex; } public int bytesBefore(byte value) { int bytes = buf().bytesBefore(value); if (bytes < 0) { throw REPLAY; } return bytes; } public int bytesBefore(ChannelBufferIndexFinder indexFinder) { int bytes = buf().bytesBefore(indexFinder); if (bytes < 0) { throw REPLAY; } return bytes; } public int bytesBefore(int length, byte value) { checkReadableBytes(length); int bytes = buf().bytesBefore(length, value); if (bytes < 0) { throw REPLAY; } return bytes; } public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) { checkReadableBytes(length); int bytes = buf().bytesBefore(length, indexFinder); if (bytes < 0) { throw REPLAY; } return bytes; } public int bytesBefore(int index, int length, byte value) { int bytes = buf().bytesBefore(index, length, value); if (bytes < 0) { throw REPLAY; } return bytes; } public int bytesBefore(int index, int length, ChannelBufferIndexFinder indexFinder) { int bytes = buf().bytesBefore(index, length, indexFinder); if (bytes < 0) { throw REPLAY; } return bytes; } public void markReaderIndex() { buf().markReaderIndex(); } public void markWriterIndex() { throw new UnreplayableOperationException(); } public ChannelBufferFactory factory() { return buf().factory(); } public ByteOrder order() { return buf().order(); } public boolean readable() { return terminated? buf().readable() : true; } public int readableBytes() { if (terminated) { return buf().readableBytes(); } else { return Integer.MAX_VALUE - buf().readerIndex(); } } public byte readByte() { checkReadableBytes(1); return buf().readByte(); } public short readUnsignedByte() { checkReadableBytes(1); return buf().readUnsignedByte(); } public void readBytes(byte[] dst, int dstIndex, int length) { checkReadableBytes(length); buf().readBytes(dst, dstIndex, length); } public void readBytes(byte[] dst) { checkReadableBytes(dst.length); buf().readBytes(dst); } public void readBytes(ByteBuffer dst) { throw new UnreplayableOperationException(); } public void readBytes(ChannelBuffer dst, int dstIndex, int length) { checkReadableBytes(length); buf().readBytes(dst, dstIndex, length); } public void readBytes(ChannelBuffer dst, int length) { throw new UnreplayableOperationException(); } public void readBytes(ChannelBuffer dst) { throw new UnreplayableOperationException(); } @Deprecated public ChannelBuffer readBytes(ChannelBufferIndexFinder endIndexFinder) { int endIndex = buf().indexOf(buf().readerIndex(), buf().writerIndex(), endIndexFinder); if (endIndex < 0) { throw REPLAY; } return buf().readBytes(endIndex - buf().readerIndex()); } public int readBytes(GatheringByteChannel out, int length) throws IOException { throw new UnreplayableOperationException(); } public ChannelBuffer readBytes(int length) { checkReadableBytes(length); return buf().readBytes(length); } @Deprecated public ChannelBuffer readSlice( ChannelBufferIndexFinder endIndexFinder) { int endIndex = buf().indexOf(buf().readerIndex(), buf().writerIndex(), endIndexFinder); if (endIndex < 0) { throw REPLAY; } return buf().readSlice(endIndex - buf().readerIndex()); } public ChannelBuffer readSlice(int length) { checkReadableBytes(length); return buf().readSlice(length); } public void readBytes(OutputStream out, int length) throws IOException { throw new UnreplayableOperationException(); } public int readerIndex() { return buf().readerIndex(); } public void readerIndex(int readerIndex) { buf().readerIndex(readerIndex); } public int readInt() { checkReadableBytes(4); return buf().readInt(); } public long readUnsignedInt() { checkReadableBytes(4); return buf().readUnsignedInt(); } public long readLong() { checkReadableBytes(8); return buf().readLong(); } public int readMedium() { checkReadableBytes(3); return buf().readMedium(); } public int readUnsignedMedium() { checkReadableBytes(3); return buf().readUnsignedMedium(); } public short readShort() { checkReadableBytes(2); return buf().readShort(); } public int readUnsignedShort() { checkReadableBytes(2); return buf().readUnsignedShort(); } public char readChar() { checkReadableBytes(2); return buf().readChar(); } public float readFloat() { checkReadableBytes(4); return buf().readFloat(); } public double readDouble() { checkReadableBytes(8); return buf().readDouble(); } public void resetReaderIndex() { buf().resetReaderIndex(); } public void resetWriterIndex() { throw new UnreplayableOperationException(); } public void setByte(int index, int value) { throw new UnreplayableOperationException(); } public void setBytes(int index, byte[] src, int srcIndex, int length) { throw new UnreplayableOperationException(); } public void setBytes(int index, byte[] src) { throw new UnreplayableOperationException(); } public void setBytes(int index, ByteBuffer src) { throw new UnreplayableOperationException(); } public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) { throw new UnreplayableOperationException(); } public void setBytes(int index, ChannelBuffer src, int length) { throw new UnreplayableOperationException(); } public void setBytes(int index, ChannelBuffer src) { throw new UnreplayableOperationException(); } public int setBytes(int index, InputStream in, int length) throws IOException { throw new UnreplayableOperationException(); } public void setZero(int index, int length) { throw new UnreplayableOperationException(); } public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { throw new UnreplayableOperationException(); } public void setIndex(int readerIndex, int writerIndex) { throw new UnreplayableOperationException(); } public void setInt(int index, int value) { throw new UnreplayableOperationException(); } public void setLong(int index, long value) { throw new UnreplayableOperationException(); } public void setMedium(int index, int value) { throw new UnreplayableOperationException(); } public void setShort(int index, int value) { throw new UnreplayableOperationException(); } public void setChar(int index, int value) { throw new UnreplayableOperationException(); } public void setFloat(int index, float value) { throw new UnreplayableOperationException(); } public void setDouble(int index, double value) { throw new UnreplayableOperationException(); } @Deprecated public int skipBytes(ChannelBufferIndexFinder firstIndexFinder) { int oldReaderIndex = buf().readerIndex(); int newReaderIndex = buf().indexOf(oldReaderIndex, buf().writerIndex(), firstIndexFinder); if (newReaderIndex < 0) { throw REPLAY; } buf().readerIndex(newReaderIndex); return newReaderIndex - oldReaderIndex; } public void skipBytes(int length) { checkReadableBytes(length); buf().skipBytes(length); } public ChannelBuffer slice() { throw new UnreplayableOperationException(); } public ChannelBuffer slice(int index, int length) { checkIndex(index, length); return buf().slice(index, length); } public ByteBuffer toByteBuffer() { throw new UnreplayableOperationException(); } public ByteBuffer toByteBuffer(int index, int length) { checkIndex(index, length); return buf().toByteBuffer(index, length); } public ByteBuffer[] toByteBuffers() { throw new UnreplayableOperationException(); } public ByteBuffer[] toByteBuffers(int index, int length) { checkIndex(index, length); return buf().toByteBuffers(index, length); } public String toString(int index, int length, Charset charset) { checkIndex(index, length); return buf().toString(index, length, charset); } public String toString(Charset charsetName) { throw new UnreplayableOperationException(); } @Deprecated public String toString(int index, int length, String charsetName) { checkIndex(index, length); return buf().toString(index, length, charsetName); } @Deprecated public String toString( int index, int length, String charsetName, ChannelBufferIndexFinder terminatorFinder) { checkIndex(index, length); return buf().toString(index, length, charsetName, terminatorFinder); } @Deprecated public String toString(String charsetName) { throw new UnreplayableOperationException(); } @Deprecated public String toString( String charsetName, ChannelBufferIndexFinder terminatorFinder) { throw new UnreplayableOperationException(); } @Override public String toString() { return getClass().getSimpleName() + '(' + "ridx=" + readerIndex() + ", " + "widx=" + writerIndex() + ')'; } public boolean writable() { return false; } public int writableBytes() { return 0; } public void writeByte(int value) { throw new UnreplayableOperationException(); } public void writeBytes(byte[] src, int srcIndex, int length) { throw new UnreplayableOperationException(); } public void writeBytes(byte[] src) { throw new UnreplayableOperationException(); } public void writeBytes(ByteBuffer src) { throw new UnreplayableOperationException(); } public void writeBytes(ChannelBuffer src, int srcIndex, int length) { throw new UnreplayableOperationException(); } public void writeBytes(ChannelBuffer src, int length) { throw new UnreplayableOperationException(); } public void writeBytes(ChannelBuffer src) { throw new UnreplayableOperationException(); } public int writeBytes(InputStream in, int length) throws IOException { throw new UnreplayableOperationException(); } public int writeBytes(ScatteringByteChannel in, int length) throws IOException { throw new UnreplayableOperationException(); } public void writeInt(int value) { throw new UnreplayableOperationException(); } public void writeLong(long value) { throw new UnreplayableOperationException(); } public void writeMedium(int value) { throw new UnreplayableOperationException(); } public void writeZero(int length) { throw new UnreplayableOperationException(); } public int writerIndex() { return buf().writerIndex(); } public void writerIndex(int writerIndex) { throw new UnreplayableOperationException(); } public void writeShort(int value) { throw new UnreplayableOperationException(); } public void writeChar(int value) { throw new UnreplayableOperationException(); } public void writeFloat(float value) { throw new UnreplayableOperationException(); } public void writeDouble(double value) { throw new UnreplayableOperationException(); } private void checkIndex(int index, int length) { if (index + length > buf().writerIndex()) { throw REPLAY; } } private void checkReadableBytes(int readableBytes) { if (buf().readableBytes() < readableBytes) { throw REPLAY; } } } UnreplayableOperationException.java000066400000000000000000000031011225554127700355270ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; import org.jboss.netty.buffer.ChannelBuffer; /** * An {@link Exception} which is thrown when a user calls an unsupported * operation on a {@link ChannelBuffer} in a {@link ReplayingDecoder} * implementation. */ public class UnreplayableOperationException extends UnsupportedOperationException { private static final long serialVersionUID = 8577363912862364021L; /** * Creates a new instance. */ public UnreplayableOperationException() { } /** * Creates a new instance. */ public UnreplayableOperationException(String message) { super(message); } /** * Creates a new instance. */ public UnreplayableOperationException(Throwable cause) { super(cause); } /** * Creates a new instance. */ public UnreplayableOperationException(String message, Throwable cause) { super(message, cause); } } UnsafeDynamicChannelBuffer.java000066400000000000000000000026521225554127700345270ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.DynamicChannelBuffer; /** * This class is not used by {@link ReplayingDecoder} anymore but is still here to not break API. * * This class will get removed in the future. * * @deprecated * */ @Deprecated class UnsafeDynamicChannelBuffer extends DynamicChannelBuffer { UnsafeDynamicChannelBuffer(ChannelBufferFactory factory, int minimumCapacity) { super(factory.getDefaultOrder(), minimumCapacity, factory); } UnsafeDynamicChannelBuffer(ChannelBufferFactory factory) { this(factory, 256); } @Override protected void checkReadableBytes(int minReaderRemaining) { // Do not check here - ReplayingDecoderBuffer will check. } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/VoidEnum.java000066400000000000000000000016411225554127700311600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; /** * A placeholder {@link Enum} which could be specified as a type parameter of * {@link ReplayingDecoder} when a user wants to manage the decoder state or * there's no state to manage. */ public enum VoidEnum { // No state is defined. } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/replay/package-info.java000066400000000000000000000020131225554127700317500ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Specialized variation of {@link org.jboss.netty.handler.codec.frame.FrameDecoder} * which enables implementation of a non-blocking decoder in the blocking I/O * paradigm. * * @apiviz.exclude ^java\.lang\. * @apiviz.exclude \.SimpleChannelUpstreamHandler$ * @apiviz.exclude \.VoidEnum$ * @apiviz.exclude \.codec\.(?!replay)[a-z0-9]+\. */ package org.jboss.netty.handler.codec.replay; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/000077500000000000000000000000001225554127700262615ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspHeaders.java000066400000000000000000000266451225554127700313650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.handler.codec.http.HttpHeaders; /** * Standard RTSP header names and values. * @apiviz.exclude * @apiviz.stereotype static */ public final class RtspHeaders { /** * Standard RTSP header names. */ public static final class Names { /** * {@code "Accept"} */ public static final String ACCEPT = HttpHeaders.Names.ACCEPT; /** * {@code "Accept-Encoding"} */ public static final String ACCEPT_ENCODING = HttpHeaders.Names.ACCEPT_ENCODING; /** * {@code "Accept-Lanugage"} */ public static final String ACCEPT_LANGUAGE = HttpHeaders.Names.ACCEPT_LANGUAGE; /** * {@code "Allow"} */ public static final String ALLOW = "Allow"; /** * {@code "Authorization"} */ public static final String AUTHORIZATION = HttpHeaders.Names.AUTHORIZATION; /** * {@code "Bandwidth"} */ public static final String BANDWIDTH = "Bandwidth"; /** * {@code "Blocksize"} */ public static final String BLOCKSIZE = "Blocksize"; /** * {@code "Cache-Control"} */ public static final String CACHE_CONTROL = HttpHeaders.Names.CACHE_CONTROL; /** * {@code "Conference"} */ public static final String CONFERENCE = "Conference"; /** * {@code "Connection"} */ public static final String CONNECTION = HttpHeaders.Names.CONNECTION; /** * {@code "Content-Base"} */ public static final String CONTENT_BASE = HttpHeaders.Names.CONTENT_BASE; /** * {@code "Content-Encoding"} */ public static final String CONTENT_ENCODING = HttpHeaders.Names.CONTENT_ENCODING; /** * {@code "Content-Language"} */ public static final String CONTENT_LANGUAGE = HttpHeaders.Names.CONTENT_LANGUAGE; /** * {@code "Content-Length"} */ public static final String CONTENT_LENGTH = HttpHeaders.Names.CONTENT_LENGTH; /** * {@code "Content-Location"} */ public static final String CONTENT_LOCATION = HttpHeaders.Names.CONTENT_LOCATION; /** * {@code "Content-Type"} */ public static final String CONTENT_TYPE = HttpHeaders.Names.CONTENT_TYPE; /** * {@code "CSeq"} */ public static final String CSEQ = "CSeq"; /** * {@code "Date"} */ public static final String DATE = HttpHeaders.Names.DATE; /** * {@code "Expires"} */ public static final String EXPIRES = HttpHeaders.Names.EXPIRES; /** * {@code "From"} */ public static final String FROM = HttpHeaders.Names.FROM; /** * {@code "Host"} */ public static final String HOST = HttpHeaders.Names.HOST; /** * {@code "If-Match"} */ public static final String IF_MATCH = HttpHeaders.Names.IF_MATCH; /** * {@code "If-Modified-Since"} */ public static final String IF_MODIFIED_SINCE = HttpHeaders.Names.IF_MODIFIED_SINCE; /** * {@code "KeyMgmt"} */ public static final String KEYMGMT = "KeyMgmt"; /** * {@code "Last-Modified"} */ public static final String LAST_MODIFIED = HttpHeaders.Names.LAST_MODIFIED; /** * {@code "Proxy-Authenticate"} */ public static final String PROXY_AUTHENTICATE = HttpHeaders.Names.PROXY_AUTHENTICATE; /** * {@code "Proxy-Require"} */ public static final String PROXY_REQUIRE = "Proxy-Require"; /** * {@code "Public"} */ public static final String PUBLIC = "Public"; /** * {@code "Range"} */ public static final String RANGE = HttpHeaders.Names.RANGE; /** * {@code "Referer"} */ public static final String REFERER = HttpHeaders.Names.REFERER; /** * {@code "Require"} */ public static final String REQUIRE = "Require"; /** * {@code "Retry-After"} */ public static final String RETRT_AFTER = HttpHeaders.Names.RETRY_AFTER; /** * {@code "RTP-Info"} */ public static final String RTP_INFO = "RTP-Info"; /** * {@code "Scale"} */ public static final String SCALE = "Scale"; /** * {@code "Session"} */ public static final String SESSION = "Session"; /** * {@code "Server"} */ public static final String SERVER = HttpHeaders.Names.SERVER; /** * {@code "Speed"} */ public static final String SPEED = "Speed"; /** * {@code "Timestamp"} */ public static final String TIMESTAMP = "Timestamp"; /** * {@code "Transport"} */ public static final String TRANSPORT = "Transport"; /** * {@code "Unsupported"} */ public static final String UNSUPPORTED = "Unsupported"; /** * {@code "User-Agent"} */ public static final String USER_AGENT = HttpHeaders.Names.USER_AGENT; /** * {@code "Vary"} */ public static final String VARY = HttpHeaders.Names.VARY; /** * {@code "Via"} */ public static final String VIA = HttpHeaders.Names.VIA; /** * {@code "WWW-Authenticate"} */ public static final String WWW_AUTHENTICATE = HttpHeaders.Names.WWW_AUTHENTICATE; private Names() { } } /** * Standard RTSP header values. */ public static final class Values { /** * {@code "append"} */ public static final String APPEND = "append"; /** * {@code "AVP"} */ public static final String AVP = "AVP"; /** * {@code "bytes"} */ public static final String BYTES = HttpHeaders.Values.BYTES; /** * {@code "charset"} */ public static final String CHARSET = HttpHeaders.Values.CHARSET; /** * {@code "client_port"} */ public static final String CLIENT_PORT = "client_port"; /** * {@code "clock"} */ public static final String CLOCK = "clock"; /** * {@code "close"} */ public static final String CLOSE = HttpHeaders.Values.CLOSE; /** * {@code "compress"} */ public static final String COMPRESS = HttpHeaders.Values.COMPRESS; /** * {@code "100-continue"} */ public static final String CONTINUE = HttpHeaders.Values.CONTINUE; /** * {@code "deflate"} */ public static final String DEFLATE = HttpHeaders.Values.DEFLATE; /** * {@code "destination"} */ public static final String DESTINATION = "destination"; /** * {@code "gzip"} */ public static final String GZIP = HttpHeaders.Values.GZIP; /** * {@code "identity"} */ public static final String IDENTITY = HttpHeaders.Values.IDENTITY; /** * {@code "interleaved"} */ public static final String INTERLEAVED = "interleaved"; /** * {@code "keep-alive"} */ public static final String KEEP_ALIVE = HttpHeaders.Values.KEEP_ALIVE; /** * {@code "layers"} */ public static final String LAYERS = "layers"; /** * {@code "max-age"} */ public static final String MAX_AGE = HttpHeaders.Values.MAX_AGE; /** * {@code "max-stale"} */ public static final String MAX_STALE = HttpHeaders.Values.MAX_STALE; /** * {@code "min-fresh"} */ public static final String MIN_FRESH = HttpHeaders.Values.MIN_FRESH; /** * {@code "mode"} */ public static final String MODE = "mode"; /** * {@code "multicast"} */ public static final String MULTICAST = "multicast"; /** * {@code "must-revalidate"} */ public static final String MUST_REVALIDATE = HttpHeaders.Values.MUST_REVALIDATE; /** * {@code "none"} */ public static final String NONE = HttpHeaders.Values.NONE; /** * {@code "no-cache"} */ public static final String NO_CACHE = HttpHeaders.Values.NO_CACHE; /** * {@code "no-transform"} */ public static final String NO_TRANSFORM = HttpHeaders.Values.NO_TRANSFORM; /** * {@code "only-if-cached"} */ public static final String ONLY_IF_CACHED = HttpHeaders.Values.ONLY_IF_CACHED; /** * {@code "port"} */ public static final String PORT = "port"; /** * {@code "private"} */ public static final String PRIVATE = HttpHeaders.Values.PRIVATE; /** * {@code "proxy-revalidate"} */ public static final String PROXY_REVALIDATE = HttpHeaders.Values.PROXY_REVALIDATE; /** * {@code "public"} */ public static final String PUBLIC = HttpHeaders.Values.PUBLIC; /** * {@code "RTP"} */ public static final String RTP = "RTP"; /** * {@code "rtptime"} */ public static final String RTPTIME = "rtptime"; /** * {@code "seq"} */ public static final String SEQ = "seq"; /** * {@code "server_port"} */ public static final String SERVER_PORT = "server_port"; /** * {@code "ssrc"} */ public static final String SSRC = "ssrc"; /** * {@code "TCP"} */ public static final String TCP = "TCP"; /** * {@code "time"} */ public static final String TIME = "time"; /** * {@code "timeout"} */ public static final String TIMEOUT = "timeout"; /** * {@code "ttl"} */ public static final String TTL = "ttl"; /** * {@code "UDP"} */ public static final String UDP = "UDP"; /** * {@code "unicast"} */ public static final String UNICAST = "unicast"; /** * {@code "url"} */ public static final String URL = "url"; protected Values() { } } private RtspHeaders() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspMessageDecoder.java000066400000000000000000000071071225554127700326540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpMessageDecoder; /** * Decodes {@link ChannelBuffer}s into RTSP messages represented in * {@link HttpMessage}s. *

*

Parameters that prevents excessive memory consumption

* * * * * * * * * * * * * * * * *
NameMeaning
{@code maxInitialLineLength}The maximum length of the initial line * (e.g. {@code "SETUP / RTSP/1.0"} or {@code "RTSP/1.0 200 OK"}) * If the length of the initial line exceeds this value, a * {@link TooLongFrameException} will be raised.
{@code maxHeaderSize}The maximum length of all headers. If the sum of the length of each * header exceeds this value, a {@link TooLongFrameException} will be raised.
{@code maxContentLength}The maximum length of the content. If the content length exceeds this * value, a {@link TooLongFrameException} will be raised.
* @apiviz.landmark */ public abstract class RtspMessageDecoder extends HttpMessageDecoder { private final DecoderEmbedder aggregator; /** * Creates a new instance with the default * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxContentLength (8192)}. */ protected RtspMessageDecoder() { this(4096, 8192, 8192); } /** * Creates a new instance with the specified parameters. */ protected RtspMessageDecoder(int maxInitialLineLength, int maxHeaderSize, int maxContentLength) { super(maxInitialLineLength, maxHeaderSize, maxContentLength * 2); aggregator = new DecoderEmbedder(new HttpChunkAggregator(maxContentLength)); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { Object o = super.decode(ctx, channel, buffer, state); if (o != null && aggregator.offer(o)) { return aggregator.poll(); } else { return null; } } @Override protected boolean isContentAlwaysEmpty(HttpMessage msg) { // Unlike HTTP, RTSP always assumes zero-length body if Content-Length // header is absent. boolean empty = super.isContentAlwaysEmpty(msg); if (empty) { return true; } if (!msg.headers().contains(RtspHeaders.Names.CONTENT_LENGTH)) { return true; } return empty; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspMessageEncoder.java000066400000000000000000000031211225554127700326560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpMessageEncoder; /** * Encodes an RTSP message represented in {@link HttpMessage} into * a {@link ChannelBuffer}. * * @apiviz.landmark */ @Sharable public abstract class RtspMessageEncoder extends HttpMessageEncoder { /** * Creates a new instance. */ protected RtspMessageEncoder() { } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { // Ignore unrelated message types such as HttpChunk. if (!(msg instanceof HttpMessage)) { return msg; } return super.encode(ctx, channel, msg); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspMethods.java000066400000000000000000000115361225554127700314060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import java.util.HashMap; import java.util.Map; import org.jboss.netty.handler.codec.http.HttpMethod; /** * The request method of RTSP. * @apiviz.exclude */ public final class RtspMethods { /** * The OPTIONS method represents a request for information about the communication options * available on the request/response chain identified by the Request-URI. This method allows * the client to determine the options and/or requirements associated with a resource, or the * capabilities of a server, without implying a resource action or initiating a resource * retrieval. */ public static final HttpMethod OPTIONS = HttpMethod.OPTIONS; /** * The DESCRIBE method retrieves the description of a presentation or * media object identified by the request URL from a server. */ public static final HttpMethod DESCRIBE = new HttpMethod("DESCRIBE"); /** * The ANNOUNCE posts the description of a presentation or media object * identified by the request URL to a server, or updates the client-side * session description in real-time. */ public static final HttpMethod ANNOUNCE = new HttpMethod("ANNOUNCE"); /** * The SETUP request for a URI specifies the transport mechanism to be * used for the streamed media. */ public static final HttpMethod SETUP = new HttpMethod("SETUP"); /** * The PLAY method tells the server to start sending data via the * mechanism specified in SETUP. */ public static final HttpMethod PLAY = new HttpMethod("PLAY"); /** * The PAUSE request causes the stream delivery to be interrupted * (halted) temporarily. */ public static final HttpMethod PAUSE = new HttpMethod("PAUSE"); /** * The TEARDOWN request stops the stream delivery for the given URI, * freeing the resources associated with it. */ public static final HttpMethod TEARDOWN = new HttpMethod("TEARDOWN"); /** * The GET_PARAMETER request retrieves the value of a parameter of a * presentation or stream specified in the URI. */ public static final HttpMethod GET_PARAMETER = new HttpMethod("GET_PARAMETER"); /** * The SET_PARAMETER requests to set the value of a parameter for a * presentation or stream specified by the URI. */ public static final HttpMethod SET_PARAMETER = new HttpMethod("SET_PARAMETER"); /** * The REDIRECT request informs the client that it must connect to another * server location. */ public static final HttpMethod REDIRECT = new HttpMethod("REDIRECT"); /** * The RECORD method initiates recording a range of media data according to * the presentation description. */ public static final HttpMethod RECORD = new HttpMethod("RECORD"); private static final Map methodMap = new HashMap(); static { methodMap.put(DESCRIBE.toString(), DESCRIBE); methodMap.put(ANNOUNCE.toString(), ANNOUNCE); methodMap.put(GET_PARAMETER.toString(), GET_PARAMETER); methodMap.put(OPTIONS.toString(), OPTIONS); methodMap.put(PAUSE.toString(), PAUSE); methodMap.put(PLAY.toString(), PLAY); methodMap.put(RECORD.toString(), RECORD); methodMap.put(REDIRECT.toString(), REDIRECT); methodMap.put(SETUP.toString(), SETUP); methodMap.put(SET_PARAMETER.toString(), SET_PARAMETER); methodMap.put(TEARDOWN.toString(), TEARDOWN); } /** * Returns the {@link HttpMethod} represented by the specified name. * If the specified name is a standard RTSP method name, a cached instance * will be returned. Otherwise, a new instance will be returned. */ public static HttpMethod valueOf(String name) { if (name == null) { throw new NullPointerException("name"); } name = name.trim().toUpperCase(); if (name.length() == 0) { throw new IllegalArgumentException("empty name"); } HttpMethod result = methodMap.get(name); if (result != null) { return result; } else { return new HttpMethod(name); } } private RtspMethods() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspRequestDecoder.java000066400000000000000000000053161225554127700327200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpRequest; /** * Decodes {@link ChannelBuffer}s into RTSP requests represented in * {@link HttpRequest}s. *

*

Parameters that prevents excessive memory consumption

* * * * * * * * * * * * * * * * *
NameMeaning
{@code maxInitialLineLength}The maximum length of the initial line (e.g. {@code "SETUP / RTSP/1.0"}) * If the length of the initial line exceeds this value, a * {@link TooLongFrameException} will be raised.
{@code maxHeaderSize}The maximum length of all headers. If the sum of the length of each * header exceeds this value, a {@link TooLongFrameException} will be raised.
{@code maxContentLength}The maximum length of the content. If the content length exceeds this * value, a {@link TooLongFrameException} will be raised.
*/ public class RtspRequestDecoder extends RtspMessageDecoder { /** * Creates a new instance with the default * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxContentLength (8192)}. */ public RtspRequestDecoder() { } /** * Creates a new instance with the specified parameters. */ public RtspRequestDecoder(int maxInitialLineLength, int maxHeaderSize, int maxContentLength) { super(maxInitialLineLength, maxHeaderSize, maxContentLength); } @Override protected HttpMessage createMessage(String[] initialLine) throws Exception { return new DefaultHttpRequest(RtspVersions.valueOf(initialLine[2]), RtspMethods.valueOf(initialLine[0]), initialLine[1]); } @Override protected boolean isDecodingRequest() { return true; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspRequestEncoder.java000066400000000000000000000030101225554127700327170ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpRequest; /** * Encodes an RTSP request represented in {@link HttpRequest} into * a {@link ChannelBuffer}. */ public class RtspRequestEncoder extends RtspMessageEncoder { @Override protected void encodeInitialLine(ChannelBuffer buf, HttpMessage message) throws Exception { HttpRequest request = (HttpRequest) message; buf.writeBytes(request.getMethod().toString().getBytes("ASCII")); buf.writeByte((byte) ' '); buf.writeBytes(request.getUri().getBytes("UTF-8")); buf.writeByte((byte) ' '); buf.writeBytes(request.getProtocolVersion().toString().getBytes("ASCII")); buf.writeByte((byte) '\r'); buf.writeByte((byte) '\n'); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspResponseDecoder.java000066400000000000000000000055051225554127700330660ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; /** * Decodes {@link ChannelBuffer}s into RTSP responses represented in * {@link HttpResponse}s. *

*

Parameters that prevents excessive memory consumption

* * * * * * * * * * * * * * * * *
NameMeaning
{@code maxInitialLineLength}The maximum length of the initial line (e.g. {@code "RTSP/1.0 200 OK"}) * If the length of the initial line exceeds this value, a * {@link TooLongFrameException} will be raised.
{@code maxHeaderSize}The maximum length of all headers. If the sum of the length of each * header exceeds this value, a {@link TooLongFrameException} will be raised.
{@code maxContentLength}The maximum length of the content. If the content length exceeds this * value, a {@link TooLongFrameException} will be raised.
*/ public class RtspResponseDecoder extends RtspMessageDecoder { /** * Creates a new instance with the default * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and * {@code maxContentLength (8192)}. */ public RtspResponseDecoder() { } /** * Creates a new instance with the specified parameters. */ public RtspResponseDecoder(int maxInitialLineLength, int maxHeaderSize, int maxContentLength) { super(maxInitialLineLength, maxHeaderSize, maxContentLength); } @Override protected HttpMessage createMessage(String[] initialLine) throws Exception { return new DefaultHttpResponse( RtspVersions.valueOf(initialLine[0]), new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2])); } @Override protected boolean isDecodingRequest() { return false; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspResponseEncoder.java000066400000000000000000000031061225554127700330730ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpResponse; /** * Encodes an RTSP response represented in {@link HttpResponse} into * a {@link ChannelBuffer}. */ public class RtspResponseEncoder extends RtspMessageEncoder { @Override protected void encodeInitialLine(ChannelBuffer buf, HttpMessage message) throws Exception { HttpResponse response = (HttpResponse) message; buf.writeBytes(response.getProtocolVersion().toString().getBytes("ASCII")); buf.writeByte((byte) ' '); buf.writeBytes(String.valueOf(response.getStatus().getCode()).getBytes("ASCII")); buf.writeByte((byte) ' '); buf.writeBytes(String.valueOf(response.getStatus().getReasonPhrase()).getBytes("ASCII")); buf.writeByte((byte) '\r'); buf.writeByte((byte) '\n'); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspResponseStatuses.java000066400000000000000000000216341225554127700333350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.handler.codec.http.HttpResponseStatus; /** * The status code and its description of a RTSP response. * @apiviz.exclude */ public final class RtspResponseStatuses { /** * 100 Continue */ public static final HttpResponseStatus CONTINUE = HttpResponseStatus.CONTINUE; /** * 200 OK */ public static final HttpResponseStatus OK = HttpResponseStatus.OK; /** * 201 Created */ public static final HttpResponseStatus CREATED = HttpResponseStatus.CREATED; /** * 250 Low on Storage Space */ public static final HttpResponseStatus LOW_STORAGE_SPACE = new HttpResponseStatus( 250, "Low on Storage Space"); /** * 300 Multiple Choices */ public static final HttpResponseStatus MULTIPLE_CHOICES = HttpResponseStatus.MULTIPLE_CHOICES; /** * 301 Moved Permanently */ public static final HttpResponseStatus MOVED_PERMANENTLY = HttpResponseStatus.MOVED_PERMANENTLY; /** * 302 Moved Temporarily */ public static final HttpResponseStatus MOVED_TEMPORARILY = new HttpResponseStatus( 302, "Moved Temporarily"); /** * 304 Not Modified */ public static final HttpResponseStatus NOT_MODIFIED = HttpResponseStatus.NOT_MODIFIED; /** * 305 Use Proxy */ public static final HttpResponseStatus USE_PROXY = HttpResponseStatus.USE_PROXY; /** * 400 Bad Request */ public static final HttpResponseStatus BAD_REQUEST = HttpResponseStatus.BAD_REQUEST; /** * 401 Unauthorized */ public static final HttpResponseStatus UNAUTHORIZED = HttpResponseStatus.UNAUTHORIZED; /** * 402 Payment Required */ public static final HttpResponseStatus PAYMENT_REQUIRED = HttpResponseStatus.PAYMENT_REQUIRED; /** * 403 Forbidden */ public static final HttpResponseStatus FORBIDDEN = HttpResponseStatus.FORBIDDEN; /** * 404 Not Found */ public static final HttpResponseStatus NOT_FOUND = HttpResponseStatus.NOT_FOUND; /** * 405 Method Not Allowed */ public static final HttpResponseStatus METHOD_NOT_ALLOWED = HttpResponseStatus.METHOD_NOT_ALLOWED; /** * 406 Not Acceptable */ public static final HttpResponseStatus NOT_ACCEPTABLE = HttpResponseStatus.NOT_ACCEPTABLE; /** * 407 Proxy Authentication Required */ public static final HttpResponseStatus PROXY_AUTHENTICATION_REQUIRED = HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; /** * 408 Request Timeout */ public static final HttpResponseStatus REQUEST_TIMEOUT = HttpResponseStatus.REQUEST_TIMEOUT; /** * 410 Gone */ public static final HttpResponseStatus GONE = HttpResponseStatus.GONE; /** * 411 Length Required */ public static final HttpResponseStatus LENGTH_REQUIRED = HttpResponseStatus.LENGTH_REQUIRED; /** * 412 Precondition Failed */ public static final HttpResponseStatus PRECONDITION_FAILED = HttpResponseStatus.PRECONDITION_FAILED; /** * 413 Request Entity Too Large */ public static final HttpResponseStatus REQUEST_ENTITY_TOO_LARGE = HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE; /** * 414 Request-URI Too Long */ public static final HttpResponseStatus REQUEST_URI_TOO_LONG = HttpResponseStatus.REQUEST_URI_TOO_LONG; /** * 415 Unsupported Media Type */ public static final HttpResponseStatus UNSUPPORTED_MEDIA_TYPE = HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE; /** * 451 Parameter Not Understood */ public static final HttpResponseStatus PARAMETER_NOT_UNDERSTOOD = new HttpResponseStatus( 451, "Parameter Not Understood"); /** * 452 Conference Not Found */ public static final HttpResponseStatus CONFERENCE_NOT_FOUND = new HttpResponseStatus( 452, "Conference Not Found"); /** * 453 Not Enough Bandwidth */ public static final HttpResponseStatus NOT_ENOUGH_BANDWIDTH = new HttpResponseStatus( 453, "Not Enough Bandwidth"); /** * 454 Session Not Found */ public static final HttpResponseStatus SESSION_NOT_FOUND = new HttpResponseStatus( 454, "Session Not Found"); /** * 455 Method Not Valid in This State */ public static final HttpResponseStatus METHOD_NOT_VALID = new HttpResponseStatus( 455, "Method Not Valid in This State"); /** * 456 Header Field Not Valid for Resource */ public static final HttpResponseStatus HEADER_FIELD_NOT_VALID = new HttpResponseStatus( 456, "Header Field Not Valid for Resource"); /** * 457 Invalid Range */ public static final HttpResponseStatus INVALID_RANGE = new HttpResponseStatus( 457, "Invalid Range"); /** * 458 Parameter Is Read-Only */ public static final HttpResponseStatus PARAMETER_IS_READONLY = new HttpResponseStatus( 458, "Parameter Is Read-Only"); /** * 459 Aggregate operation not allowed */ public static final HttpResponseStatus AGGREGATE_OPERATION_NOT_ALLOWED = new HttpResponseStatus( 459, "Aggregate operation not allowed"); /** * 460 Only Aggregate operation allowed */ public static final HttpResponseStatus ONLY_AGGREGATE_OPERATION_ALLOWED = new HttpResponseStatus( 460, "Only Aggregate operation allowed"); /** * 461 Unsupported transport */ public static final HttpResponseStatus UNSUPPORTED_TRANSPORT = new HttpResponseStatus( 461, "Unsupported transport"); /** * 462 Destination unreachable */ public static final HttpResponseStatus DESTINATION_UNREACHABLE = new HttpResponseStatus( 462, "Destination unreachable"); /** * 463 Key management failure */ public static final HttpResponseStatus KEY_MANAGEMENT_FAILURE = new HttpResponseStatus( 463, "Key management failure"); /** * 500 Internal Server Error */ public static final HttpResponseStatus INTERNAL_SERVER_ERROR = HttpResponseStatus.INTERNAL_SERVER_ERROR; /** * 501 Not Implemented */ public static final HttpResponseStatus NOT_IMPLEMENTED = HttpResponseStatus.NOT_IMPLEMENTED; /** * 502 Bad Gateway */ public static final HttpResponseStatus BAD_GATEWAY = HttpResponseStatus.BAD_GATEWAY; /** * 503 Service Unavailable */ public static final HttpResponseStatus SERVICE_UNAVAILABLE = HttpResponseStatus.SERVICE_UNAVAILABLE; /** * 504 Gateway Timeout */ public static final HttpResponseStatus GATEWAY_TIMEOUT = HttpResponseStatus.GATEWAY_TIMEOUT; /** * 505 RTSP Version not supported */ public static final HttpResponseStatus RTSP_VERSION_NOT_SUPPORTED = new HttpResponseStatus( 505, "RTSP Version not supported"); /** * 551 Option not supported */ public static final HttpResponseStatus OPTION_NOT_SUPPORTED = new HttpResponseStatus( 551, "Option not supported"); /** * Returns the {@link HttpResponseStatus} represented by the specified code. * If the specified code is a standard RTSP status code, a cached instance * will be returned. Otherwise, a new instance will be returned. */ public static HttpResponseStatus valueOf(int code) { switch (code) { case 250: return LOW_STORAGE_SPACE; case 302: return MOVED_TEMPORARILY; case 451: return PARAMETER_NOT_UNDERSTOOD; case 452: return CONFERENCE_NOT_FOUND; case 453: return NOT_ENOUGH_BANDWIDTH; case 454: return SESSION_NOT_FOUND; case 455: return METHOD_NOT_VALID; case 456: return HEADER_FIELD_NOT_VALID; case 457: return INVALID_RANGE; case 458: return PARAMETER_IS_READONLY; case 459: return AGGREGATE_OPERATION_NOT_ALLOWED; case 460: return ONLY_AGGREGATE_OPERATION_ALLOWED; case 461: return UNSUPPORTED_TRANSPORT; case 462: return DESTINATION_UNREACHABLE; case 463: return KEY_MANAGEMENT_FAILURE; case 505: return RTSP_VERSION_NOT_SUPPORTED; case 551: return OPTION_NOT_SUPPORTED; default: return HttpResponseStatus.valueOf(code); } } private RtspResponseStatuses() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/RtspVersions.java000066400000000000000000000031071225554127700316060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.rtsp; import org.jboss.netty.handler.codec.http.HttpVersion; /** * The version of RTSP. * @apiviz.exclude */ public final class RtspVersions { /** * RTSP/1.0 */ public static final HttpVersion RTSP_1_0 = new HttpVersion("RTSP", 1, 0, true); /** * Returns an existing or new {@link HttpVersion} instance which matches to * the specified RTSP version string. If the specified {@code text} is * equal to {@code "RTSP/1.0"}, {@link #RTSP_1_0} will be returned. * Otherwise, a new {@link HttpVersion} instance will be returned. */ public static HttpVersion valueOf(String text) { if (text == null) { throw new NullPointerException("text"); } text = text.trim().toUpperCase(); if ("RTSP/1.0".equals(text)) { return RTSP_1_0; } return new HttpVersion(text, true); } private RtspVersions() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/rtsp/package-info.java000066400000000000000000000015171225554127700314540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * An RTSP * extension based on the HTTP codec. * * @apiviz.exclude \.RtspHeaders\. */ package org.jboss.netty.handler.codec.rtsp; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/000077500000000000000000000000001225554127700301465ustar00rootroot00000000000000CachingClassResolver.java000066400000000000000000000026171225554127700350040ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.Map; class CachingClassResolver implements ClassResolver { private final Map> classCache; private final ClassResolver delegate; CachingClassResolver(ClassResolver delegate, Map> classCache) { this.delegate = delegate; this.classCache = classCache; } public Class resolve(String className) throws ClassNotFoundException { // Query the cache first. Class clazz; clazz = classCache.get(className); if (clazz != null) { return clazz; } // And then try to load. clazz = delegate.resolve(className); classCache.put(className, clazz); return clazz; } } ClassLoaderClassResolver.java000066400000000000000000000022211225554127700356330ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; class ClassLoaderClassResolver implements ClassResolver { private final ClassLoader classLoader; ClassLoaderClassResolver(ClassLoader classLoader) { this.classLoader = classLoader; } public Class resolve(String className) throws ClassNotFoundException { try { return classLoader.loadClass(className); } catch (ClassNotFoundException e) { return Class.forName(className, false, classLoader); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/ClassResolver.java000066400000000000000000000015351225554127700336040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; /** * please use {@link ClassResolvers} as instance factory */ public interface ClassResolver { Class resolve(String className) throws ClassNotFoundException; } ClassResolvers.java000066400000000000000000000076121225554127700337120ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.lang.ref.Reference; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; public final class ClassResolvers { /** * cache disabled * @param classLoader - specific classLoader to use, or null if you want to revert to default * @return new instance of class resolver */ public static ClassResolver cacheDisabled(ClassLoader classLoader) { return new ClassLoaderClassResolver(defaultClassLoader(classLoader)); } /** * non-agressive non-concurrent cache * good for non-shared default cache * * @param classLoader - specific classLoader to use, or null if you want to revert to default * @return new instance of class resolver */ public static ClassResolver weakCachingResolver(ClassLoader classLoader) { return new CachingClassResolver( new ClassLoaderClassResolver(defaultClassLoader(classLoader)), new WeakReferenceMap>(new HashMap>>())); } /** * agressive non-concurrent cache * good for non-shared cache, when we're not worried about class unloading * * @param classLoader - specific classLoader to use, or null if you want to revert to default * @return new instance of class resolver */ public static ClassResolver softCachingResolver(ClassLoader classLoader) { return new CachingClassResolver( new ClassLoaderClassResolver(defaultClassLoader(classLoader)), new SoftReferenceMap>(new HashMap>>())); } /** * non-agressive concurrent cache * good for shared cache, when we're worried about class unloading * * @param classLoader - specific classLoader to use, or null if you want to revert to default * @return new instance of class resolver */ public static ClassResolver weakCachingConcurrentResolver(ClassLoader classLoader) { return new CachingClassResolver( new ClassLoaderClassResolver(defaultClassLoader(classLoader)), new WeakReferenceMap>(new ConcurrentHashMap>>())); } /** * agressive concurrent cache * good for shared cache, when we're not worried about class unloading * * @param classLoader - specific classLoader to use, or null if you want to revert to default * @return new instance of class resolver */ public static ClassResolver softCachingConcurrentResolver(ClassLoader classLoader) { return new CachingClassResolver( new ClassLoaderClassResolver(defaultClassLoader(classLoader)), new SoftReferenceMap>(new ConcurrentHashMap>>())); } static ClassLoader defaultClassLoader(ClassLoader classLoader) { if (classLoader != null) { return classLoader; } final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null) { return contextClassLoader; } return ClassResolvers.class.getClassLoader(); } private ClassResolvers() { // Unused } } CompactObjectInputStream.java000066400000000000000000000064631225554127700356540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.io.StreamCorruptedException; class CompactObjectInputStream extends ObjectInputStream { private final ClassResolver classResolver; CompactObjectInputStream(InputStream in, ClassResolver classResolver) throws IOException { super(in); if (classResolver == null) { throw new NullPointerException("classResolver"); } this.classResolver = classResolver; } @Override protected void readStreamHeader() throws IOException { int version = readByte() & 0xFF; if (version != STREAM_VERSION) { throw new StreamCorruptedException( "Unsupported version: " + version); } } @Override protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { int type = read(); if (type < 0) { throw new EOFException(); } switch (type) { case CompactObjectOutputStream.TYPE_FAT_DESCRIPTOR: return super.readClassDescriptor(); case CompactObjectOutputStream.TYPE_THIN_DESCRIPTOR: String className = readUTF(); Class clazz = classResolver.resolve(className); ObjectStreamClass streamClass = ObjectStreamClass.lookup(clazz); if (streamClass == null) { // If streamClass is null its very likely that we had an old netty version that was writing an // interface with a thin descriptor. Fall back to use ObjectStreamClazz.lookupAny(..) to resolve // it. // // This will only work on java6+ but if we hit this line its very likely that a user is upgrading // from netty 3.2.x which was using the method before and so use java6+. // // See https://github.com/netty/netty/commit/6c2eba79d70a532822a0e38092faa9783d90906b streamClass = ObjectStreamClass.lookupAny(clazz); } return streamClass; default: throw new StreamCorruptedException( "Unexpected class descriptor type: " + type); } } @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { Class clazz; try { clazz = classResolver.resolve(desc.getName()); } catch (ClassNotFoundException ex) { clazz = super.resolveClass(desc); } return clazz; } } CompactObjectOutputStream.java000066400000000000000000000031611225554127700360450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.OutputStream; class CompactObjectOutputStream extends ObjectOutputStream { static final int TYPE_FAT_DESCRIPTOR = 0; static final int TYPE_THIN_DESCRIPTOR = 1; CompactObjectOutputStream(OutputStream out) throws IOException { super(out); } @Override protected void writeStreamHeader() throws IOException { writeByte(STREAM_VERSION); } @Override protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException { Class clazz = desc.forClass(); if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || desc.getSerialVersionUID() == 0) { write(TYPE_FAT_DESCRIPTOR); super.writeClassDescriptor(desc); } else { write(TYPE_THIN_DESCRIPTOR); writeUTF(desc.getName()); } } } CompatibleObjectDecoder.java000066400000000000000000000104641225554127700354330ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamConstants; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferInputStream; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; /** * A decoder which deserializes the received {@link ChannelBuffer}s into Java * objects (interoperability version). *

* This decoder is interoperable with the standard Java object * streams such as {@link ObjectInputStream} and {@link ObjectOutputStream}. *

* However, this decoder might perform worse than {@link ObjectDecoder} if * the serialized object is big and complex. Also, it does not limit the * maximum size of the object, and consequently your application might face * the risk of DoS attack. * Please use {@link ObjectEncoder} and {@link ObjectDecoder} if you are not * required to keep the interoperability with the standard object streams. * * @deprecated This decoder has a known critical bug which fails to decode and * raises a random exception in some circumstances. Avoid to use * it whenever you can. The only workaround is to replace * {@link CompatibleObjectEncoder}, {@link CompatibleObjectDecoder}, * {@link ObjectInputStream}, and {@link ObjectOutputStream} with * {@link ObjectEncoder}, {@link ObjectDecoder}, * {@link ObjectEncoderOutputStream}, and * {@link ObjectDecoderInputStream} respectively. This workaround * requires both a client and a server to be modified. */ @Deprecated public class CompatibleObjectDecoder extends ReplayingDecoder { private final SwitchableInputStream bin = new SwitchableInputStream(); private ObjectInputStream oin; /** * Creates a new decoder. */ public CompatibleObjectDecoder() { super(CompatibleObjectDecoderState.READ_HEADER); } /** * Creates a new {@link ObjectInputStream} which wraps the specified * {@link InputStream}. Override this method to use a subclass of the * {@link ObjectInputStream}. */ protected ObjectInputStream newObjectInputStream(InputStream in) throws Exception { return new ObjectInputStream(in); } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, CompatibleObjectDecoderState state) throws Exception { bin.switchStream(new ChannelBufferInputStream(buffer)); switch (state) { case READ_HEADER: oin = newObjectInputStream(bin); checkpoint(CompatibleObjectDecoderState.READ_OBJECT); case READ_OBJECT: return oin.readObject(); default: throw new IllegalStateException("Unknown state: " + state); } } @Override protected Object decodeLast(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, CompatibleObjectDecoderState state) throws Exception { switch (buffer.readableBytes()) { case 0: return null; case 1: // Ignore the last TC_RESET if (buffer.getByte(buffer.readerIndex()) == ObjectStreamConstants.TC_RESET) { buffer.skipBytes(1); oin.close(); return null; } } Object decoded = decode(ctx, channel, buffer, state); oin.close(); return decoded; } } CompatibleObjectDecoderState.java000066400000000000000000000013711225554127700364310ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; enum CompatibleObjectDecoderState { READ_HEADER, READ_OBJECT, } CompatibleObjectEncoder.java000066400000000000000000000104361225554127700354440ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.concurrent.atomic.AtomicReference; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBufferOutputStream; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * An encoder which serializes a Java object into a {@link ChannelBuffer} * (interoperability version). *

* This encoder is interoperable with the standard Java object streams such as * {@link ObjectInputStream} and {@link ObjectOutputStream}. */ public class CompatibleObjectEncoder extends OneToOneEncoder { private final AtomicReference buffer = new AtomicReference(); private final int resetInterval; private volatile ObjectOutputStream oout; private int writtenObjects; /** * Creates a new instance with the reset interval of {@code 16}. */ public CompatibleObjectEncoder() { this(16); // Reset at every sixteen writes } /** * Creates a new instance. * * @param resetInterval * the number of objects between {@link ObjectOutputStream#reset()}. * {@code 0} will disable resetting the stream, but the remote * peer will be at the risk of getting {@link OutOfMemoryError} in * the long term. */ public CompatibleObjectEncoder(int resetInterval) { if (resetInterval < 0) { throw new IllegalArgumentException( "resetInterval: " + resetInterval); } this.resetInterval = resetInterval; } /** * Creates a new {@link ObjectOutputStream} which wraps the specified * {@link OutputStream}. Override this method to use a subclass of the * {@link ObjectOutputStream}. */ protected ObjectOutputStream newObjectOutputStream(OutputStream out) throws Exception { return new ObjectOutputStream(out); } @Override protected Object encode(ChannelHandlerContext context, Channel channel, Object msg) throws Exception { ChannelBuffer buffer = buffer(context); ObjectOutputStream oout = this.oout; if (resetInterval != 0) { // Resetting will prevent OOM on the receiving side. writtenObjects ++; if (writtenObjects % resetInterval == 0) { oout.reset(); // Also discard the byproduct to avoid OOM on the sending side. buffer.discardReadBytes(); } } oout.writeObject(msg); oout.flush(); ChannelBuffer encoded = buffer.readBytes(buffer.readableBytes()); return encoded; } private ChannelBuffer buffer(ChannelHandlerContext ctx) throws Exception { ChannelBuffer buf = buffer.get(); if (buf == null) { ChannelBufferFactory factory = ctx.getChannel().getConfig().getBufferFactory(); buf = ChannelBuffers.dynamicBuffer(factory); if (buffer.compareAndSet(null, buf)) { boolean success = false; try { oout = newObjectOutputStream(new ChannelBufferOutputStream(buf)); success = true; } finally { if (!success) { oout = null; } } } else { buf = buffer.get(); } } return buf; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/ObjectDecoder.java000066400000000000000000000120771225554127700335140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.ObjectOutputStream; import java.io.StreamCorruptedException; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferInputStream; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; /** * A decoder which deserializes the received {@link ChannelBuffer}s into Java * objects. *

* Please note that the serialized form this decoder expects is not * compatible with the standard {@link ObjectOutputStream}. Please use * {@link ObjectEncoder} or {@link ObjectEncoderOutputStream} to ensure the * interoperability with this decoder. * * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.serialization.ObjectDecoderInputStream - - - compatible with */ public class ObjectDecoder extends LengthFieldBasedFrameDecoder { private final ClassResolver classResolver; /** * Creates a new decoder whose maximum object size is {@code 1048576} * bytes. If the size of the received object is greater than * {@code 1048576} bytes, a {@link StreamCorruptedException} will be * raised. * * @deprecated use {@link #ObjectDecoder(ClassResolver)} */ @Deprecated public ObjectDecoder() { this(1048576); } /** * Creates a new decoder whose maximum object size is {@code 1048576} * bytes. If the size of the received object is greater than * {@code 1048576} bytes, a {@link StreamCorruptedException} will be * raised. * * @param classResolver the {@link ClassResolver} to use for this decoder */ public ObjectDecoder(ClassResolver classResolver) { this(1048576, classResolver); } /** * Creates a new decoder with the specified maximum object size. * * @param maxObjectSize the maximum byte length of the serialized object. * if the length of the received object is greater * than this value, {@link StreamCorruptedException} * will be raised. * @deprecated use {@link #ObjectDecoder(int, ClassResolver)} */ @Deprecated public ObjectDecoder(int maxObjectSize) { this(maxObjectSize, ClassResolvers.weakCachingResolver(null)); } /** * Creates a new decoder with the specified maximum object size. * * @param maxObjectSize the maximum byte length of the serialized object. * if the length of the received object is greater * than this value, {@link StreamCorruptedException} * will be raised. * @param classResolver the {@link ClassResolver} which will load the class * of the serialized object */ public ObjectDecoder(int maxObjectSize, ClassResolver classResolver) { super(maxObjectSize, 0, 4, 0, 4); if (classResolver == null) { throw new NullPointerException("classResolver"); } this.classResolver = classResolver; } /** * Create a new decoder with the specified maximum object size and the {@link ClassLoader} * wrapped in {@link ClassResolvers#weakCachingResolver(ClassLoader)}. * * @param maxObjectSize the maximum byte length of the serialized object. * if the length of the received object is greater * than this value, {@link StreamCorruptedException} * will be raised. * @param classLoader the the classloader to use * @deprecated use {@link #ObjectDecoder(int, ClassResolver)} */ @Deprecated public ObjectDecoder(int maxObjectSize, ClassLoader classLoader) { this(maxObjectSize, ClassResolvers.weakCachingResolver(classLoader)); } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { ChannelBuffer frame = (ChannelBuffer) super.decode(ctx, channel, buffer); if (frame == null) { return null; } return new CompactObjectInputStream( new ChannelBufferInputStream(frame), classResolver).readObject(); } @Override protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length) { return buffer.slice(index, length); } } ObjectDecoderInputStream.java000066400000000000000000000144211225554127700356240ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; import java.io.StreamCorruptedException; /** * An {@link ObjectInput} which is interoperable with {@link ObjectEncoder} * and {@link ObjectEncoderOutputStream}. */ public class ObjectDecoderInputStream extends InputStream implements ObjectInput { private final DataInputStream in; private final int maxObjectSize; private final ClassResolver classResolver; /** * Creates a new {@link ObjectInput}. * * @param in * the {@link InputStream} where the serialized form will be * read from */ public ObjectDecoderInputStream(InputStream in) { this(in, null); } /** * Creates a new {@link ObjectInput}. * * @param in * the {@link InputStream} where the serialized form will be * read from * @param classLoader * the {@link ClassLoader} which will load the class of the * serialized object */ public ObjectDecoderInputStream(InputStream in, ClassLoader classLoader) { this(in, classLoader, 1048576); } /** * Creates a new {@link ObjectInput}. * * @param in * the {@link InputStream} where the serialized form will be * read from * @param maxObjectSize * the maximum byte length of the serialized object. if the length * of the received object is greater than this value, * a {@link StreamCorruptedException} will be raised. */ public ObjectDecoderInputStream(InputStream in, int maxObjectSize) { this(in, null, maxObjectSize); } /** * Creates a new {@link ObjectInput}. * * @param in * the {@link InputStream} where the serialized form will be * read from * @param classLoader * the {@link ClassLoader} which will load the class of the * serialized object * @param maxObjectSize * the maximum byte length of the serialized object. if the length * of the received object is greater than this value, * a {@link StreamCorruptedException} will be raised. */ public ObjectDecoderInputStream(InputStream in, ClassLoader classLoader, int maxObjectSize) { if (in == null) { throw new NullPointerException("in"); } if (maxObjectSize <= 0) { throw new IllegalArgumentException("maxObjectSize: " + maxObjectSize); } if (in instanceof DataInputStream) { this.in = (DataInputStream) in; } else { this.in = new DataInputStream(in); } classResolver = ClassResolvers.weakCachingResolver(classLoader); this.maxObjectSize = maxObjectSize; } public Object readObject() throws ClassNotFoundException, IOException { int dataLen = readInt(); if (dataLen <= 0) { throw new StreamCorruptedException("invalid data length: " + dataLen); } if (dataLen > maxObjectSize) { throw new StreamCorruptedException( "data length too big: " + dataLen + " (max: " + maxObjectSize + ')'); } return new CompactObjectInputStream(in, classResolver).readObject(); } @Override public int available() throws IOException { return in.available(); } @Override public void close() throws IOException { in.close(); } @Override public void mark(int readlimit) { in.mark(readlimit); } @Override public boolean markSupported() { return in.markSupported(); } @Override public int read() throws IOException { return in.read(); } @Override public final int read(byte[] b, int off, int len) throws IOException { return in.read(b, off, len); } @Override public final int read(byte[] b) throws IOException { return in.read(b); } public final boolean readBoolean() throws IOException { return in.readBoolean(); } public final byte readByte() throws IOException { return in.readByte(); } public final char readChar() throws IOException { return in.readChar(); } public final double readDouble() throws IOException { return in.readDouble(); } public final float readFloat() throws IOException { return in.readFloat(); } public final void readFully(byte[] b, int off, int len) throws IOException { in.readFully(b, off, len); } public final void readFully(byte[] b) throws IOException { in.readFully(b); } public final int readInt() throws IOException { return in.readInt(); } @Deprecated public final String readLine() throws IOException { return in.readLine(); } public final long readLong() throws IOException { return in.readLong(); } public final short readShort() throws IOException { return in.readShort(); } public final int readUnsignedByte() throws IOException { return in.readUnsignedByte(); } public final int readUnsignedShort() throws IOException { return in.readUnsignedShort(); } public final String readUTF() throws IOException { return in.readUTF(); } @Override public void reset() throws IOException { in.reset(); } @Override public long skip(long n) throws IOException { return in.skip(n); } public final int skipBytes(int n) throws IOException { return in.skipBytes(n); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/ObjectEncoder.java000066400000000000000000000063761225554127700335330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import static org.jboss.netty.buffer.ChannelBuffers.*; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * An encoder which serializes a Java object into a {@link ChannelBuffer}. *

* Please note that the serialized form this encoder produces is not * compatible with the standard {@link ObjectInputStream}. Please use * {@link ObjectDecoder} or {@link ObjectDecoderInputStream} to ensure the * interoperability with this encoder. * * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.codec.serialization.ObjectEncoderOutputStream - - - compatible with */ @Sharable public class ObjectEncoder extends OneToOneEncoder { private static final byte[] LENGTH_PLACEHOLDER = new byte[4]; private final int estimatedLength; /** * Creates a new encoder with the estimated length of 512 bytes. */ public ObjectEncoder() { this(512); } /** * Creates a new encoder. * * @param estimatedLength * the estimated byte length of the serialized form of an object. * If the length of the serialized form exceeds this value, the * internal buffer will be expanded automatically at the cost of * memory bandwidth. If this value is too big, it will also waste * memory bandwidth. To avoid unnecessary memory copy or allocation * cost, please specify the properly estimated value. */ public ObjectEncoder(int estimatedLength) { if (estimatedLength < 0) { throw new IllegalArgumentException( "estimatedLength: " + estimatedLength); } this.estimatedLength = estimatedLength; } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { ChannelBufferOutputStream bout = new ChannelBufferOutputStream(dynamicBuffer( estimatedLength, ctx.getChannel().getConfig().getBufferFactory())); bout.write(LENGTH_PLACEHOLDER); ObjectOutputStream oout = new CompactObjectOutputStream(bout); oout.writeObject(msg); oout.flush(); oout.close(); ChannelBuffer encoded = bout.buffer(); encoded.setInt(0, encoded.writerIndex() - 4); return encoded; } } ObjectEncoderOutputStream.java000066400000000000000000000115151225554127700360400ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; import org.jboss.netty.buffer.ChannelBuffers; /** * An {@link ObjectOutput} which is interoperable with {@link ObjectDecoder} * and {@link ObjectDecoderInputStream}. */ public class ObjectEncoderOutputStream extends OutputStream implements ObjectOutput { private final DataOutputStream out; private final int estimatedLength; /** * Creates a new {@link ObjectOutput} with the estimated length of 512 * bytes. * * @param out * the {@link OutputStream} where the serialized form will be * written out */ public ObjectEncoderOutputStream(OutputStream out) { this(out, 512); } /** * Creates a new {@link ObjectOutput}. * * @param out * the {@link OutputStream} where the serialized form will be * written out * * @param estimatedLength * the estimated byte length of the serialized form of an object. * If the length of the serialized form exceeds this value, the * internal buffer will be expanded automatically at the cost of * memory bandwidth. If this value is too big, it will also waste * memory bandwidth. To avoid unnecessary memory copy or allocation * cost, please specify the properly estimated value. */ public ObjectEncoderOutputStream(OutputStream out, int estimatedLength) { if (out == null) { throw new NullPointerException("out"); } if (estimatedLength < 0) { throw new IllegalArgumentException("estimatedLength: " + estimatedLength); } if (out instanceof DataOutputStream) { this.out = (DataOutputStream) out; } else { this.out = new DataOutputStream(out); } this.estimatedLength = estimatedLength; } public void writeObject(Object obj) throws IOException { ChannelBufferOutputStream bout = new ChannelBufferOutputStream( ChannelBuffers.dynamicBuffer(estimatedLength)); ObjectOutputStream oout = new CompactObjectOutputStream(bout); oout.writeObject(obj); oout.flush(); oout.close(); ChannelBuffer buffer = bout.buffer(); int objectSize = buffer.readableBytes(); writeInt(objectSize); buffer.getBytes(0, this, objectSize); } @Override public void write(int b) throws IOException { out.write(b); } @Override public void close() throws IOException { out.close(); } @Override public void flush() throws IOException { out.flush(); } public final int size() { return out.size(); } @Override public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); } @Override public void write(byte[] b) throws IOException { out.write(b); } public final void writeBoolean(boolean v) throws IOException { out.writeBoolean(v); } public final void writeByte(int v) throws IOException { out.writeByte(v); } public final void writeBytes(String s) throws IOException { out.writeBytes(s); } public final void writeChar(int v) throws IOException { out.writeChar(v); } public final void writeChars(String s) throws IOException { out.writeChars(s); } public final void writeDouble(double v) throws IOException { out.writeDouble(v); } public final void writeFloat(float v) throws IOException { out.writeFloat(v); } public final void writeInt(int v) throws IOException { out.writeInt(v); } public final void writeLong(long v) throws IOException { out.writeLong(v); } public final void writeShort(int v) throws IOException { out.writeShort(v); } public final void writeUTF(String str) throws IOException { out.writeUTF(str); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/ReferenceMap.java000066400000000000000000000044141225554127700333500ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.lang.ref.Reference; import java.util.Collection; import java.util.Map; import java.util.Set; abstract class ReferenceMap implements Map { private final Map> delegate; protected ReferenceMap(Map> delegate) { this.delegate = delegate; } abstract Reference fold(V value); private V unfold(Reference ref) { if (ref == null) { return null; } return ref.get(); } public int size() { return delegate.size(); } public boolean isEmpty() { return delegate.isEmpty(); } public boolean containsKey(Object key) { return delegate.containsKey(key); } public boolean containsValue(Object value) { throw new UnsupportedOperationException(); } public V get(Object key) { return unfold(delegate.get(key)); } public V put(K key, V value) { return unfold(delegate.put(key, fold(value))); } public V remove(Object key) { return unfold(delegate.remove(key)); } public void putAll(Map m) { for (Entry entry : m.entrySet()) { delegate.put(entry.getKey(), fold(entry.getValue())); } } public void clear() { delegate.clear(); } public Set keySet() { return delegate.keySet(); } public Collection values() { throw new UnsupportedOperationException(); } public Set> entrySet() { throw new UnsupportedOperationException(); } } SoftReferenceMap.java000066400000000000000000000020171225554127700341220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.util.Map; public class SoftReferenceMap extends ReferenceMap { public SoftReferenceMap(Map> delegate) { super(delegate); } @Override Reference fold(V value) { return new SoftReference(value); } } SwitchableInputStream.java000066400000000000000000000023641225554127700352200ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.FilterInputStream; import java.io.InputStream; /** * {@link FilterInputStream} which allows a user to change the underlying * stream at any time. */ final class SwitchableInputStream extends FilterInputStream { /** * Creates a new instance without initializing the reference to the * underlying stream. */ SwitchableInputStream() { super(null); } /** * Creates a new instance with the initial reference to the underlying * stream. */ void switchStream(InputStream in) { this.in = in; } } WeakReferenceMap.java000066400000000000000000000020171225554127700340760ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.Map; public class WeakReferenceMap extends ReferenceMap { public WeakReferenceMap(Map> delegate) { super(delegate); } @Override Reference fold(V value) { return new WeakReference(value); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/serialization/package-info.java000066400000000000000000000016661225554127700333460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder, decoder and their compatibility stream implementations which * transform a {@link java.io.Serializable} object into a byte buffer and * vice versa. * * @apiviz.exclude ^java\.io\. * @apiviz.exclude \.codec\.(?!serialization)[a-z0-9]+\. */ package org.jboss.netty.handler.codec.serialization; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/000077500000000000000000000000001225554127700264135ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksAuthRequest.java000066400000000000000000000056151225554127700325420ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.util.CharsetUtil; import java.nio.charset.CharsetEncoder; /** * An socks auth request. * * @see {@link SocksAuthResponse} * @see {@link SocksAuthRequestDecoder} */ public final class SocksAuthRequest extends SocksRequest { private static final CharsetEncoder asciiEncoder = CharsetUtil.getEncoder(CharsetUtil.US_ASCII); private static final SubnegotiationVersion SUBNEGOTIATION_VERSION = SubnegotiationVersion.AUTH_PASSWORD; private final String username; private final String password; public SocksAuthRequest(String username, String password) { super(SocksRequestType.AUTH); if (username == null) { throw new NullPointerException("username"); } if (password == null) { throw new NullPointerException("username"); } if (!asciiEncoder.canEncode(username) || !asciiEncoder.canEncode(password)) { throw new IllegalArgumentException(" username: " + username + " or password: " + password + " values should be in pure ascii"); } if (username.length() > 255) { throw new IllegalArgumentException(username + " exceeds 255 char limit"); } if (password.length() > 255) { throw new IllegalArgumentException(password + " exceeds 255 char limit"); } this.username = username; this.password = password; } /** * Returns username that needs to be authenticated * * @return username that needs to be authenticated */ public String getUsername() { return username; } /** * Returns password that needs to be validated * * @return password that needs to be validated */ public String getPassword() { return password; } @Override public void encodeAsByteBuf(ChannelBuffer channelBuffer) throws Exception { channelBuffer.writeByte(SUBNEGOTIATION_VERSION.getByteValue()); channelBuffer.writeByte(username.length()); channelBuffer.writeBytes(username.getBytes("US-ASCII")); channelBuffer.writeByte(password.length()); channelBuffer.writeBytes(password.getBytes("US-ASCII")); } } SocksAuthRequestDecoder.java000066400000000000000000000053411225554127700337450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.util.CharsetUtil; /** * Decodes {@link ChannelBuffer}s into {@link SocksAuthRequest}. * Before returning SocksRequest decoder removes itself from pipeline. */ public class SocksAuthRequestDecoder extends ReplayingDecoder { private static final String name = "SOCKS_AUTH_REQUEST_DECODER"; public static String getName() { return name; } private SocksMessage.SubnegotiationVersion version; private int fieldLength; private String username; private String password; private SocksRequest msg = SocksCommonUtils.UNKNOWN_SOCKS_REQUEST; public SocksAuthRequestDecoder() { super(State.CHECK_PROTOCOL_VERSION); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case CHECK_PROTOCOL_VERSION: { version = SocksMessage.SubnegotiationVersion.fromByte(buffer.readByte()); if (version != SocksMessage.SubnegotiationVersion.AUTH_PASSWORD) { break; } checkpoint(State.READ_USERNAME); } case READ_USERNAME: { fieldLength = buffer.readByte(); username = buffer.readBytes(fieldLength).toString(CharsetUtil.US_ASCII); checkpoint(State.READ_PASSWORD); } case READ_PASSWORD: { fieldLength = buffer.readByte(); password = buffer.readBytes(fieldLength).toString(CharsetUtil.US_ASCII); msg = new SocksAuthRequest(username, password); } } ctx.getPipeline().remove(this); return msg; } enum State { CHECK_PROTOCOL_VERSION, READ_USERNAME, READ_PASSWORD } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksAuthResponse.java000066400000000000000000000031661225554127700327070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An socks auth response. * * @see SocksAuthRequest * @see SocksAuthResponseDecoder */ public final class SocksAuthResponse extends SocksResponse { private static final SubnegotiationVersion SUBNEGOTIATION_VERSION = SubnegotiationVersion.AUTH_PASSWORD; private final AuthStatus authStatus; public SocksAuthResponse(AuthStatus authStatus) { super(SocksResponseType.AUTH); if (authStatus == null) { throw new NullPointerException("authStatus"); } this.authStatus = authStatus; } /** * Returns the {@link AuthStatus} of this {@link SocksAuthResponse} */ public AuthStatus getAuthStatus() { return authStatus; } @Override public void encodeAsByteBuf(ChannelBuffer channelBuffer) { channelBuffer.writeByte(SUBNEGOTIATION_VERSION.getByteValue()); channelBuffer.writeByte(authStatus.getByteValue()); } } SocksAuthResponseDecoder.java000066400000000000000000000045561225554127700341220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; /** * Decodes {@link ChannelBuffer}s into {@link SocksAuthResponse}. * Before returning SocksResponse decoder removes itself from pipeline. */ public class SocksAuthResponseDecoder extends ReplayingDecoder { private static final String name = "SOCKS_AUTH_RESPONSE_DECODER"; public static String getName() { return name; } private SocksMessage.SubnegotiationVersion version; private SocksMessage.AuthStatus authStatus; private SocksResponse msg = SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE; public SocksAuthResponseDecoder() { super(State.CHECK_PROTOCOL_VERSION); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case CHECK_PROTOCOL_VERSION: { version = SocksMessage.SubnegotiationVersion.fromByte(buffer.readByte()); if (version != SocksMessage.SubnegotiationVersion.AUTH_PASSWORD) { break; } checkpoint(State.READ_AUTH_RESPONSE); } case READ_AUTH_RESPONSE: { authStatus = SocksMessage.AuthStatus.fromByte(buffer.readByte()); msg = new SocksAuthResponse(authStatus); } } ctx.getPipeline().remove(this); return msg; } public enum State { CHECK_PROTOCOL_VERSION, READ_AUTH_RESPONSE } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksCmdRequest.java000066400000000000000000000104741225554127700323430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.util.NetUtil; import org.jboss.netty.util.internal.DetectionUtil; import java.net.IDN; /** * An socks cmd request. * * @see {@link SocksCmdResponse} * @see {@link SocksCmdRequestDecoder} */ public final class SocksCmdRequest extends SocksRequest { private final CmdType cmdType; private final AddressType addressType; private final String host; private final int port; public SocksCmdRequest(CmdType cmdType, AddressType addressType, String host, int port) { super(SocksRequestType.CMD); if (DetectionUtil.javaVersion() < 6) { throw new IllegalStateException("Only supported with Java version 6+"); } if (cmdType == null) { throw new NullPointerException("cmdType"); } if (addressType == null) { throw new NullPointerException("addressType"); } if (host == null) { throw new NullPointerException("host"); } switch (addressType) { case IPv4: if (!NetUtil.isValidIpV4Address(host)) { throw new IllegalArgumentException(host + " is not a valid IPv4 address"); } break; case DOMAIN: if (IDN.toASCII(host).length() > 255) { throw new IllegalArgumentException(host + " IDN: " + IDN.toASCII(host) + " exceeds 255 char limit"); } break; case IPv6: if (!NetUtil.isValidIpV6Address(host)) { throw new IllegalArgumentException(host + " is not a valid IPv6 address"); } break; case UNKNOWN: break; } if (port < 0 && port >= 65535) { throw new IllegalArgumentException(port + " is not in bounds 0 < x < 65536"); } this.cmdType = cmdType; this.addressType = addressType; this.host = IDN.toASCII(host); this.port = port; } /** * Returns the {@link SocksMessage.CmdType} of this {@link SocksCmdRequest} */ public CmdType getCmdType() { return cmdType; } /** * Returns the {@link AddressType} of this {@link SocksCmdRequest} */ public AddressType getAddressType() { return addressType; } /** * Returns host that is used as a parameter in {@link SocksMessage.CmdType} */ public String getHost() { return IDN.toUnicode(host); } /** * Returns port that is used as a parameter in {@link SocksMessage.CmdType} */ public int getPort() { return port; } @Override public void encodeAsByteBuf(ChannelBuffer channelBuffer) throws Exception { channelBuffer.writeByte(getProtocolVersion().getByteValue()); channelBuffer.writeByte(cmdType.getByteValue()); channelBuffer.writeByte(0x00); channelBuffer.writeByte(addressType.getByteValue()); switch (addressType) { case IPv4: { channelBuffer.writeBytes(NetUtil.createByteArrayFromIpAddressString(host)); channelBuffer.writeShort(port); break; } case DOMAIN: { channelBuffer.writeByte(host.length()); channelBuffer.writeBytes(host.getBytes("US-ASCII")); channelBuffer.writeShort(port); break; } case IPv6: { channelBuffer.writeBytes(NetUtil.createByteArrayFromIpAddressString(host)); channelBuffer.writeShort(port); break; } } } } SocksCmdRequestDecoder.java000066400000000000000000000074401225554127700335510ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.util.CharsetUtil; /** * Decodes {@link ChannelBuffer}s into {@link SocksCmdRequest}. * Before returning SocksRequest decoder removes itself from pipeline. */ public class SocksCmdRequestDecoder extends ReplayingDecoder { private static final String name = "SOCKS_CMD_REQUEST_DECODER"; public static String getName() { return name; } private SocksMessage.ProtocolVersion version; private int fieldLength; private SocksMessage.CmdType cmdType; private SocksMessage.AddressType addressType; private byte reserved; private String host; private int port; private SocksRequest msg = SocksCommonUtils.UNKNOWN_SOCKS_REQUEST; public SocksCmdRequestDecoder() { super(State.CHECK_PROTOCOL_VERSION); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case CHECK_PROTOCOL_VERSION: { version = SocksMessage.ProtocolVersion.fromByte(buffer.readByte()); if (version != SocksMessage.ProtocolVersion.SOCKS5) { break; } checkpoint(State.READ_CMD_HEADER); } case READ_CMD_HEADER: { cmdType = SocksMessage.CmdType.fromByte(buffer.readByte()); reserved = buffer.readByte(); addressType = SocksMessage.AddressType.fromByte(buffer.readByte()); checkpoint(State.READ_CMD_ADDRESS); } case READ_CMD_ADDRESS: { switch (addressType) { case IPv4: { host = SocksCommonUtils.intToIp(buffer.readInt()); port = buffer.readUnsignedShort(); msg = new SocksCmdRequest(cmdType, addressType, host, port); break; } case DOMAIN: { fieldLength = buffer.readByte(); host = buffer.readBytes(fieldLength).toString(CharsetUtil.US_ASCII); port = buffer.readUnsignedShort(); msg = new SocksCmdRequest(cmdType, addressType, host, port); break; } case IPv6: { host = SocksCommonUtils.ipv6toStr(buffer.readBytes(16).array()); port = buffer.readUnsignedShort(); msg = new SocksCmdRequest(cmdType, addressType, host, port); break; } case UNKNOWN: break; } } } ctx.getPipeline().remove(this); return msg; } enum State { CHECK_PROTOCOL_VERSION, READ_CMD_HEADER, READ_CMD_ADDRESS } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksCmdResponse.java000066400000000000000000000061261225554127700325100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An socks cmd response. * * @see SocksCmdRequest * @see SocksCmdResponseDecoder */ public final class SocksCmdResponse extends SocksResponse { private final CmdStatus cmdStatus; private final AddressType addressType; // All arrays are initialized on construction time to 0/false/null remove array Initialization private static final byte[] IPv4_HOSTNAME_ZEROED = {0x00, 0x00, 0x00, 0x00}; private static final byte[] IPv6_HOSTNAME_ZEROED = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; public SocksCmdResponse(CmdStatus cmdStatus, AddressType addressType) { super(SocksResponseType.CMD); if (cmdStatus == null) { throw new NullPointerException("cmdStatus"); } if (addressType == null) { throw new NullPointerException("addressType"); } this.cmdStatus = cmdStatus; this.addressType = addressType; } /** * Returns the {@link CmdStatus} of this {@link SocksCmdResponse} * * @return The {@link CmdStatus} of this {@link SocksCmdResponse} */ public CmdStatus getCmdStatus() { return cmdStatus; } /** * Returns the {@link AddressType} of this {@link SocksCmdResponse} * * @return The {@link AddressType} of this {@link SocksCmdResponse} */ public AddressType getAddressType() { return addressType; } @Override public void encodeAsByteBuf(ChannelBuffer channelBuffer) { channelBuffer.writeByte(getProtocolVersion().getByteValue()); channelBuffer.writeByte(cmdStatus.getByteValue()); channelBuffer.writeByte(0x00); channelBuffer.writeByte(addressType.getByteValue()); switch (addressType) { case IPv4: { channelBuffer.writeBytes(IPv4_HOSTNAME_ZEROED); channelBuffer.writeShort(0); break; } case DOMAIN: { channelBuffer.writeByte(1); // domain length channelBuffer.writeByte(0); // domain value channelBuffer.writeShort(0); // port value break; } case IPv6: { channelBuffer.writeBytes(IPv6_HOSTNAME_ZEROED); channelBuffer.writeShort(0); break; } } } } SocksCmdResponseDecoder.java000066400000000000000000000074341225554127700337220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import org.jboss.netty.util.CharsetUtil; /** * Decodes {@link ChannelBuffer}s into {@link SocksCmdResponse}. * Before returning SocksResponse decoder removes itself from pipeline. */ public class SocksCmdResponseDecoder extends ReplayingDecoder { private static final String name = "SOCKS_CMD_RESPONSE_DECODER"; public static String getName() { return name; } private SocksMessage.ProtocolVersion version; private int fieldLength; private SocksMessage.CmdStatus cmdStatus; private SocksMessage.AddressType addressType; private byte reserved; private String host; private int port; private SocksResponse msg = SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE; public SocksCmdResponseDecoder() { super(State.CHECK_PROTOCOL_VERSION); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case CHECK_PROTOCOL_VERSION: { version = SocksMessage.ProtocolVersion.fromByte(buffer.readByte()); if (version != SocksMessage.ProtocolVersion.SOCKS5) { break; } checkpoint(State.READ_CMD_HEADER); } case READ_CMD_HEADER: { cmdStatus = SocksMessage.CmdStatus.fromByte(buffer.readByte()); reserved = buffer.readByte(); addressType = SocksMessage.AddressType.fromByte(buffer.readByte()); checkpoint(State.READ_CMD_ADDRESS); } case READ_CMD_ADDRESS: { switch (addressType) { case IPv4: { host = SocksCommonUtils.intToIp(buffer.readInt()); port = buffer.readUnsignedShort(); msg = new SocksCmdResponse(cmdStatus, addressType); break; } case DOMAIN: { fieldLength = buffer.readByte(); host = buffer.readBytes(fieldLength).toString(CharsetUtil.US_ASCII); port = buffer.readUnsignedShort(); msg = new SocksCmdResponse(cmdStatus, addressType); break; } case IPv6: { host = SocksCommonUtils.ipv6toStr(buffer.readBytes(16).array()); port = buffer.readUnsignedShort(); msg = new SocksCmdResponse(cmdStatus, addressType); break; } case UNKNOWN: break; } } } ctx.getPipeline().remove(this); return msg; } public enum State { CHECK_PROTOCOL_VERSION, READ_CMD_HEADER, READ_CMD_ADDRESS } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksCommonUtils.java000066400000000000000000000073371225554127700325440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; final class SocksCommonUtils { public static final SocksRequest UNKNOWN_SOCKS_REQUEST = new UnknownSocksRequest(); public static final SocksResponse UNKNOWN_SOCKS_RESPONSE = new UnknownSocksResponse(); private static final int SECOND_ADDRESS_OCTET_SHIFT = 16; private static final int FIRST_ADDRESS_OCTET_SHIFT = 24; private static final int THIRD_ADDRESS_OCTET_SHIFT = 8; private static final int XOR_DEFAULT_VALUE = 0xff; /** * A constructor to stop this class being constructed. */ private SocksCommonUtils() { //NOOP } public static String intToIp(int i) { return String.valueOf(i >> FIRST_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' + (i >> SECOND_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' + (i >> THIRD_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' + (i & XOR_DEFAULT_VALUE); } private static final char[] ipv6conseqZeroFiller = {':', ':'}; private static final char ipv6hextetSeparator = ':'; /* * Convert numeric IPv6 to compressed format, where * the longest sequence of 0's (with 2 or more 0's) is replaced with "::" */ public static String ipv6toCompressedForm(byte[] src) { assert src.length == 16; //Find the longest sequence of 0's //start of compressed region (hextet index) int cmprHextet = -1; //length of compressed region int cmprSize = 0; for (int hextet = 0; hextet < 8;) { int curByte = hextet * 2; int size = 0; while (curByte < src.length && src[curByte] == 0 && src[curByte + 1] == 0) { curByte += 2; size++; } if (size > cmprSize) { cmprHextet = hextet; cmprSize = size; } hextet = curByte / 2 + 1; } if (cmprHextet == -1 || cmprSize < 2) { //No compression can be applied return ipv6toStr(src); } StringBuilder sb = new StringBuilder(39); ipv6toStr(sb, src, 0, cmprHextet); sb.append(ipv6conseqZeroFiller); ipv6toStr(sb, src, cmprHextet + cmprSize, 8); return sb.toString(); } /* * Convert numeric IPv6 to standard (non-compressed) format. * * Borrowed from Inet6Address.java #numericToTextFormat(byte[]) * Changed StringBuffer -> StringBuilder and ":" -> ':' for performance. */ public static String ipv6toStr(byte[] src) { assert src.length == 16; StringBuilder sb = new StringBuilder(39); ipv6toStr(sb, src, 0, 8); return sb.toString(); } private static void ipv6toStr(StringBuilder sb, byte[] src, int fromHextet, int toHextet) { for (int i = fromHextet; i < toHextet; i++) { sb.append(Integer.toHexString(src[i << 1] << 8 & 0xff00 | src[(i << 1) + 1] & 0xff)); if (i < toHextet - 1) { sb.append(ipv6hextetSeparator); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksInitRequest.java000066400000000000000000000033751225554127700325450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import java.util.Collections; import java.util.List; /** * An socks init request. * * @see {@link SocksInitResponse} * @see {@link SocksInitRequestDecoder} */ public final class SocksInitRequest extends SocksRequest { private final List authSchemes; public SocksInitRequest(List authSchemes) { super(SocksRequestType.INIT); if (authSchemes == null) { throw new NullPointerException("authSchemes"); } this.authSchemes = authSchemes; } /** * Returns the List<{@link AuthScheme}> of this {@link SocksInitRequest} */ public List getAuthSchemes() { return Collections.unmodifiableList(authSchemes); } @Override public void encodeAsByteBuf(ChannelBuffer channelBuffer) { channelBuffer.writeByte(getProtocolVersion().getByteValue()); channelBuffer.writeByte(authSchemes.size()); for (AuthScheme authScheme : authSchemes) { channelBuffer.writeByte(authScheme.getByteValue()); } } } SocksInitRequestDecoder.java000066400000000000000000000052221225554127700337450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; import java.util.ArrayList; import java.util.List; /** * Decodes {@link ChannelBuffer}s into {@link SocksInitRequest}. * Before returning SocksRequest decoder removes itself from pipeline. */ public class SocksInitRequestDecoder extends ReplayingDecoder { private static final String name = "SOCKS_INIT_REQUEST_DECODER"; public static String getName() { return name; } private final List authSchemes = new ArrayList(); private SocksMessage.ProtocolVersion version; private byte authSchemeNum; private SocksRequest msg = SocksCommonUtils.UNKNOWN_SOCKS_REQUEST; public SocksInitRequestDecoder() { super(State.CHECK_PROTOCOL_VERSION); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case CHECK_PROTOCOL_VERSION: { version = SocksMessage.ProtocolVersion.fromByte(buffer.readByte()); if (version != SocksMessage.ProtocolVersion.SOCKS5) { break; } checkpoint(State.READ_AUTH_SCHEMES); } case READ_AUTH_SCHEMES: { authSchemes.clear(); authSchemeNum = buffer.readByte(); for (int i = 0; i < authSchemeNum; i++) { authSchemes.add(SocksMessage.AuthScheme.fromByte(buffer.readByte())); } msg = new SocksInitRequest(authSchemes); break; } } ctx.getPipeline().remove(this); return msg; } enum State { CHECK_PROTOCOL_VERSION, READ_AUTH_SCHEMES } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksInitResponse.java000066400000000000000000000030271225554127700327050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An socks init response. * * @see {@link SocksInitRequest} * @see {@link SocksInitResponseDecoder} */ public final class SocksInitResponse extends SocksResponse { private final AuthScheme authScheme; public SocksInitResponse(AuthScheme authScheme) { super(SocksResponseType.INIT); if (authScheme == null) { throw new NullPointerException("authScheme"); } this.authScheme = authScheme; } /** * Returns the {@link AuthScheme} of this {@link SocksInitResponse} */ public AuthScheme getAuthScheme() { return authScheme; } @Override public void encodeAsByteBuf(ChannelBuffer channelBuffer) { channelBuffer.writeByte(getProtocolVersion().getByteValue()); channelBuffer.writeByte(authScheme.getByteValue()); } } SocksInitResponseDecoder.java000066400000000000000000000045771225554127700341270ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; /** * Decodes {@link ChannelBuffer}s into {@link SocksInitResponse}. * Before returning SocksResponse decoder removes itself from pipeline. */ public class SocksInitResponseDecoder extends ReplayingDecoder { private static final String name = "SOCKS_INIT_RESPONSE_DECODER"; public static String getName() { return name; } private SocksMessage.ProtocolVersion version; private SocksMessage.AuthScheme authScheme; private SocksResponse msg = SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE; public SocksInitResponseDecoder() { super(State.CHECK_PROTOCOL_VERSION); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception { switch (state) { case CHECK_PROTOCOL_VERSION: { version = SocksMessage.ProtocolVersion.fromByte(buffer.readByte()); if (version != SocksMessage.ProtocolVersion.SOCKS5) { break; } checkpoint(State.READ_PREFFERED_AUTH_TYPE); } case READ_PREFFERED_AUTH_TYPE: { authScheme = SocksMessage.AuthScheme.fromByte(buffer.readByte()); msg = new SocksInitResponse(authScheme); break; } } ctx.getPipeline().remove(this); return msg; } public enum State { CHECK_PROTOCOL_VERSION, READ_PREFFERED_AUTH_TYPE } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksMessage.java000066400000000000000000000137701225554127700316550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An abstract class that defines a SocksMessage, providing common properties for * {@link SocksRequest} and {@link SocksResponse}. * * @see SocksRequest * @see SocksResponse */ public abstract class SocksMessage { private final MessageType messageType; private final ProtocolVersion protocolVersion = ProtocolVersion.SOCKS5; protected SocksMessage(MessageType messageType) { if (messageType == null) { throw new NullPointerException("messageType"); } this.messageType = messageType; } /** * Returns the {@link MessageType} of this {@link SocksMessage} * * @return The {@link MessageType} of this {@link SocksMessage} */ public MessageType getMessageType() { return messageType; } public enum MessageType { REQUEST, RESPONSE, UNKNOWN } public enum AuthScheme { NO_AUTH((byte) 0x00), AUTH_GSSAPI((byte) 0x01), AUTH_PASSWORD((byte) 0x02), UNKNOWN((byte) 0xff); private final byte b; AuthScheme(byte b) { this.b = b; } public static AuthScheme fromByte(byte b) { for (AuthScheme code : values()) { if (code.b == b) { return code; } } return UNKNOWN; } public byte getByteValue() { return b; } } public enum CmdType { CONNECT((byte) 0x01), BIND((byte) 0x02), UDP((byte) 0x03), UNKNOWN((byte) 0xff); private final byte b; CmdType(byte b) { this.b = b; } public static CmdType fromByte(byte b) { for (CmdType code : values()) { if (code.b == b) { return code; } } return UNKNOWN; } public byte getByteValue() { return b; } } public enum AddressType { IPv4((byte) 0x01), DOMAIN((byte) 0x03), IPv6((byte) 0x04), UNKNOWN((byte) 0xff); private final byte b; AddressType(byte b) { this.b = b; } public static AddressType fromByte(byte b) { for (AddressType code : values()) { if (code.b == b) { return code; } } return UNKNOWN; } public byte getByteValue() { return b; } } public enum AuthStatus { SUCCESS((byte) 0x00), FAILURE((byte) 0xff); private final byte b; AuthStatus(byte b) { this.b = b; } public static AuthStatus fromByte(byte b) { for (AuthStatus code : values()) { if (code.b == b) { return code; } } return FAILURE; } public byte getByteValue() { return b; } } public enum CmdStatus { SUCCESS((byte) 0x00), FAILURE((byte) 0x01), FORBIDDEN((byte) 0x02), NETWORK_UNREACHABLE((byte) 0x03), HOST_UNREACHABLE((byte) 0x04), REFUSED((byte) 0x05), TTL_EXPIRED((byte) 0x06), COMMAND_NOT_SUPPORTED((byte) 0x07), ADDRESS_NOT_SUPPORTED((byte) 0x08), UNASSIGNED((byte) 0xff); private final byte b; CmdStatus(byte b) { this.b = b; } public static CmdStatus fromByte(byte b) { for (CmdStatus code : values()) { if (code.b == b) { return code; } } return UNASSIGNED; } public byte getByteValue() { return b; } } public enum ProtocolVersion { SOCKS4a((byte) 0x04), SOCKS5((byte) 0x05), UNKNOWN((byte) 0xff); private final byte b; ProtocolVersion(byte b) { this.b = b; } public static ProtocolVersion fromByte(byte b) { for (ProtocolVersion code : values()) { if (code.b == b) { return code; } } return UNKNOWN; } public byte getByteValue() { return b; } } public enum SubnegotiationVersion { AUTH_PASSWORD((byte) 0x01), UNKNOWN((byte) 0xff); private final byte b; SubnegotiationVersion(byte b) { this.b = b; } public static SubnegotiationVersion fromByte(byte b) { for (SubnegotiationVersion code : values()) { if (code.b == b) { return code; } } return UNKNOWN; } public byte getByteValue() { return b; } } /** * Returns the {@link ProtocolVersion} of this {@link SocksMessage} * * @return The {@link ProtocolVersion} of this {@link SocksMessage} */ public ProtocolVersion getProtocolVersion() { return protocolVersion; } /** * Encode socks message into its byte representation and write it into byteBuf * * @see ChannelBuffer */ public abstract void encodeAsByteBuf(ChannelBuffer channelBuffer) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksMessageEncoder.java000066400000000000000000000035761225554127700331600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; /** * Encodes an {@link SocksMessage} into a {@link ChannelBuffer}. * {@link OneToOneEncoder} implementation. * Use this with {@link SocksInitRequest}, {@link SocksInitResponse}, {@link SocksAuthRequest}, * {@link SocksAuthResponse}, {@link SocksCmdRequest} and {@link SocksCmdResponse} */ @ChannelHandler.Sharable public class SocksMessageEncoder extends OneToOneEncoder { private static final String name = "SOCKS_MESSAGE_ENCODER"; private static final int DEFAULT_ENCODER_BUFFER_SIZE = 1024; public static String getName() { return name; } @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { ChannelBuffer buffer = null; if (msg instanceof SocksMessage) { buffer = ChannelBuffers.buffer(DEFAULT_ENCODER_BUFFER_SIZE); ((SocksMessage) msg).encodeAsByteBuf(buffer); } return buffer; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksRequest.java000066400000000000000000000033031225554127700317100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; /** * An abstract class that defines a SocksRequest, providing common properties for * {@link SocksInitRequest}, {@link SocksAuthRequest}, {@link SocksCmdRequest} and {@link UnknownSocksRequest}. * * @see {@link SocksInitRequest} * @see {@link SocksAuthRequest} * @see {@link SocksCmdRequest} * @see {@link UnknownSocksRequest} */ public abstract class SocksRequest extends SocksMessage { private final SocksRequestType socksRequestType; protected SocksRequest(SocksRequestType socksRequestType) { super(MessageType.REQUEST); if (socksRequestType == null) { throw new NullPointerException("socksRequestType"); } this.socksRequestType = socksRequestType; } /** * Returns socks request type * * @return socks request type */ public SocksRequestType getSocksRequestType() { return socksRequestType; } /** * Type of socks request */ public enum SocksRequestType { INIT, AUTH, CMD, UNKNOWN } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/SocksResponse.java000066400000000000000000000033361225554127700320640ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; /** * An abstract class that defines a SocksResponse, providing common properties for * {@link SocksInitResponse}, {@link SocksAuthResponse}, {@link SocksCmdResponse} and {@link UnknownSocksResponse}. * * @see {@link SocksInitResponse} * @see {@link SocksAuthResponse} * @see {@link SocksCmdResponse} * @see {@link UnknownSocksResponse} */ public abstract class SocksResponse extends SocksMessage { private final SocksResponseType socksResponseType; protected SocksResponse(SocksResponseType socksResponseType) { super(MessageType.RESPONSE); if (socksResponseType == null) { throw new NullPointerException("socksResponseType"); } this.socksResponseType = socksResponseType; } /** * Returns socks response type * * @return socks response type */ public SocksResponseType getSocksResponseType() { return socksResponseType; } /** * Type of socks response */ public enum SocksResponseType { INIT, AUTH, CMD, UNKNOWN } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/UnknownSocksMessage.java000066400000000000000000000020641225554127700332270ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An unknown socks message. * * @see {@link UnknownSocksRequest} * @see {@link UnknownSocksResponse} */ public final class UnknownSocksMessage extends SocksMessage { public UnknownSocksMessage() { super(MessageType.UNKNOWN); } @Override public void encodeAsByteBuf(ChannelBuffer byteBuf) { // NOOP } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/UnknownSocksRequest.java000066400000000000000000000021461225554127700332740ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An unknown socks request. * * @see {@link SocksInitRequestDecoder} * @see {@link SocksAuthRequestDecoder} * @see {@link SocksCmdRequestDecoder} */ public final class UnknownSocksRequest extends SocksRequest { public UnknownSocksRequest() { super(SocksRequestType.UNKNOWN); } @Override public void encodeAsByteBuf(ChannelBuffer buffer) { // NOOP } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/UnknownSocksResponse.java000066400000000000000000000021561225554127700334430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; /** * An unknown socks response. * * @see {@link SocksInitResponseDecoder} * @see {@link SocksAuthResponseDecoder} * @see {@link SocksCmdResponseDecoder} */ public final class UnknownSocksResponse extends SocksResponse { public UnknownSocksResponse() { super(SocksResponseType.UNKNOWN); } @Override public void encodeAsByteBuf(ChannelBuffer buffer) { // NOOP } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/socks/package-info.java000066400000000000000000000014401225554127700316010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder, decoder and their related message types for Socks. * * Be aware it is only supported on Java 6+. */ package org.jboss.netty.handler.codec.socks; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/000077500000000000000000000000001225554127700262505ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/DefaultSpdyDataFrame.java000066400000000000000000000042011225554127700331010ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdyDataFrame} implementation. */ public class DefaultSpdyDataFrame extends DefaultSpdyStreamFrame implements SpdyDataFrame { private ChannelBuffer data = ChannelBuffers.EMPTY_BUFFER; /** * Creates a new instance. * * @param streamId the Stream-ID of this frame */ public DefaultSpdyDataFrame(int streamId) { super(streamId); } public ChannelBuffer getData() { return data; } public void setData(ChannelBuffer data) { if (data == null) { data = ChannelBuffers.EMPTY_BUFFER; } if (data.readableBytes() > SpdyCodecUtil.SPDY_MAX_LENGTH) { throw new IllegalArgumentException("data payload cannot exceed " + SpdyCodecUtil.SPDY_MAX_LENGTH + " bytes"); } this.data = data; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(last: "); buf.append(isLast()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append("--> Stream-ID = "); buf.append(getStreamId()); buf.append(StringUtil.NEWLINE); buf.append("--> Size = "); buf.append(getData().readableBytes()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/DefaultSpdyGoAwayFrame.java000066400000000000000000000053731225554127700334320ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdyGoAwayFrame} implementation. */ public class DefaultSpdyGoAwayFrame implements SpdyGoAwayFrame { private int lastGoodStreamId; private SpdySessionStatus status; /** * Creates a new instance. * * @param lastGoodStreamId the Last-good-stream-ID of this frame */ public DefaultSpdyGoAwayFrame(int lastGoodStreamId) { this(lastGoodStreamId, 0); } /** * Creates a new instance. * * @param lastGoodStreamId the Last-good-stream-ID of this frame * @param statusCode the Status code of this frame */ public DefaultSpdyGoAwayFrame(int lastGoodStreamId, int statusCode) { this(lastGoodStreamId, SpdySessionStatus.valueOf(statusCode)); } /** * Creates a new instance. * * @param lastGoodStreamId the Last-good-stream-ID of this frame * @param status the status of this frame */ public DefaultSpdyGoAwayFrame(int lastGoodStreamId, SpdySessionStatus status) { setLastGoodStreamId(lastGoodStreamId); setStatus(status); } public int getLastGoodStreamId() { return lastGoodStreamId; } public void setLastGoodStreamId(int lastGoodStreamId) { if (lastGoodStreamId < 0) { throw new IllegalArgumentException("Last-good-stream-ID" + " cannot be negative: " + lastGoodStreamId); } this.lastGoodStreamId = lastGoodStreamId; } public SpdySessionStatus getStatus() { return status; } public void setStatus(SpdySessionStatus status) { this.status = status; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append(StringUtil.NEWLINE); buf.append("--> Last-good-stream-ID = "); buf.append(getLastGoodStreamId()); buf.append(StringUtil.NEWLINE); buf.append("--> Status: "); buf.append(getStatus().toString()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/DefaultSpdyHeaders.java000066400000000000000000000233721225554127700326420ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeSet; import java.util.Map.Entry; public class DefaultSpdyHeaders extends SpdyHeaders { private static final int BUCKET_SIZE = 17; private static int hash(String name) { int h = 0; for (int i = name.length() - 1; i >= 0; i --) { char c = name.charAt(i); if (c >= 'A' && c <= 'Z') { c += 32; } h = 31 * h + c; } if (h > 0) { return h; } else if (h == Integer.MIN_VALUE) { return Integer.MAX_VALUE; } else { return -h; } } private static boolean eq(String name1, String name2) { int nameLen = name1.length(); if (nameLen != name2.length()) { return false; } for (int i = nameLen - 1; i >= 0; i --) { char c1 = name1.charAt(i); char c2 = name2.charAt(i); if (c1 != c2) { if (c1 >= 'A' && c1 <= 'Z') { c1 += 32; } if (c2 >= 'A' && c2 <= 'Z') { c2 += 32; } if (c1 != c2) { return false; } } } return true; } private static int index(int hash) { return hash % BUCKET_SIZE; } private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE]; private final HeaderEntry head = new HeaderEntry(-1, null, null); DefaultSpdyHeaders() { head.before = head.after = head; } @Override public SpdyHeaders add(final String name, final Object value) { String lowerCaseName = name.toLowerCase(); SpdyCodecUtil.validateHeaderName(lowerCaseName); String strVal = toString(value); SpdyCodecUtil.validateHeaderValue(strVal); int h = hash(lowerCaseName); int i = index(h); add0(h, i, lowerCaseName, strVal); return this; } private void add0(int h, int i, final String name, final String value) { // Update the hash table. HeaderEntry e = entries[i]; HeaderEntry newEntry; entries[i] = newEntry = new HeaderEntry(h, name, value); newEntry.next = e; // Update the linked list. newEntry.addBefore(head); } @Override public SpdyHeaders remove(final String name) { if (name == null) { throw new NullPointerException("name"); } String lowerCaseName = name.toLowerCase(); int h = hash(lowerCaseName); int i = index(h); remove0(h, i, lowerCaseName); return this; } private void remove0(int h, int i, String name) { HeaderEntry e = entries[i]; if (e == null) { return; } for (;;) { if (e.hash == h && eq(name, e.key)) { e.remove(); HeaderEntry next = e.next; if (next != null) { entries[i] = next; e = next; } else { entries[i] = null; return; } } else { break; } } for (;;) { HeaderEntry next = e.next; if (next == null) { break; } if (next.hash == h && eq(name, next.key)) { e.next = next.next; next.remove(); } else { e = next; } } } @Override public SpdyHeaders set(final String name, final Object value) { String lowerCaseName = name.toLowerCase(); SpdyCodecUtil.validateHeaderName(lowerCaseName); String strVal = toString(value); SpdyCodecUtil.validateHeaderValue(strVal); int h = hash(lowerCaseName); int i = index(h); remove0(h, i, lowerCaseName); add0(h, i, lowerCaseName, strVal); return this; } @Override public SpdyHeaders set(final String name, final Iterable values) { if (values == null) { throw new NullPointerException("values"); } String lowerCaseName = name.toLowerCase(); SpdyCodecUtil.validateHeaderName(lowerCaseName); int h = hash(lowerCaseName); int i = index(h); remove0(h, i, lowerCaseName); for (Object v: values) { if (v == null) { break; } String strVal = toString(v); SpdyCodecUtil.validateHeaderValue(strVal); add0(h, i, lowerCaseName, strVal); } return this; } @Override public SpdyHeaders clear() { for (int i = 0; i < entries.length; i ++) { entries[i] = null; } head.before = head.after = head; return this; } @Override public String get(final String name) { if (name == null) { throw new NullPointerException("name"); } int h = hash(name); int i = index(h); HeaderEntry e = entries[i]; while (e != null) { if (e.hash == h && eq(name, e.key)) { return e.value; } e = e.next; } return null; } @Override public List getAll(final String name) { if (name == null) { throw new NullPointerException("name"); } LinkedList values = new LinkedList(); int h = hash(name); int i = index(h); HeaderEntry e = entries[i]; while (e != null) { if (e.hash == h && eq(name, e.key)) { values.addFirst(e.value); } e = e.next; } return values; } @Override public List> entries() { List> all = new LinkedList>(); HeaderEntry e = head.after; while (e != head) { all.add(e); e = e.after; } return all; } @Override public Iterator> iterator() { return new HeaderIterator(); } @Override public boolean contains(String name) { return get(name) != null; } @Override public Set names() { Set names = new TreeSet(); HeaderEntry e = head.after; while (e != head) { names.add(e.key); e = e.after; } return names; } @Override public SpdyHeaders add(String name, Iterable values) { SpdyCodecUtil.validateHeaderValue(name); int h = hash(name); int i = index(h); for (Object v: values) { String vstr = toString(v); SpdyCodecUtil.validateHeaderValue(vstr); add0(h, i, name, vstr); } return this; } @Override public boolean isEmpty() { return head == head.after; } private static String toString(Object value) { if (value == null) { return null; } return value.toString(); } private final class HeaderIterator implements Iterator> { private HeaderEntry current = head; @Override public boolean hasNext() { return current.after != head; } @Override public Entry next() { current = current.after; if (current == head) { throw new NoSuchElementException(); } return current; } @Override public void remove() { throw new UnsupportedOperationException(); } } private static final class HeaderEntry implements Map.Entry { final int hash; final String key; String value; HeaderEntry next; HeaderEntry before, after; HeaderEntry(int hash, String key, String value) { this.hash = hash; this.key = key; this.value = value; } void remove() { before.after = after; after.before = before; } void addBefore(HeaderEntry e) { after = e; before = e.before; before.after = this; after.before = this; } @Override public String getKey() { return key; } @Override public String getValue() { return value; } @Override public String setValue(String value) { if (value == null) { throw new NullPointerException("value"); } SpdyCodecUtil.validateHeaderValue(value); String oldValue = this.value; this.value = value; return oldValue; } @Override public String toString() { return key + '=' + value; } } } DefaultSpdyHeadersFrame.java000066400000000000000000000071141225554127700335320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdyHeadersFrame} implementation. */ public class DefaultSpdyHeadersFrame extends DefaultSpdyStreamFrame implements SpdyHeadersFrame { private boolean invalid; private boolean truncated; private final SpdyHeaders headers = new DefaultSpdyHeaders(); /** * Creates a new instance. * * @param streamId the Stream-ID of this frame */ public DefaultSpdyHeadersFrame(int streamId) { super(streamId); } public boolean isInvalid() { return invalid; } public void setInvalid() { invalid = true; } public boolean isTruncated() { return truncated; } public void setTruncated() { truncated = true; } public SpdyHeaders headers() { return headers; } @Deprecated public void addHeader(final String name, final Object value) { headers.add(name, value); } @Deprecated public void setHeader(final String name, final Object value) { headers.set(name, value); } @Deprecated public void setHeader(final String name, final Iterable values) { headers.set(name, values); } @Deprecated public void removeHeader(final String name) { headers.remove(name); } @Deprecated public void clearHeaders() { headers.clear(); } @Deprecated public String getHeader(final String name) { return headers.get(name); } @Deprecated public List getHeaders(final String name) { return headers.getAll(name); } @Deprecated public List> getHeaders() { return headers.entries(); } @Deprecated public boolean containsHeader(final String name) { return headers.contains(name); } @Deprecated public Set getHeaderNames() { return headers.names(); } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(last: "); buf.append(isLast()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append("--> Stream-ID = "); buf.append(getStreamId()); buf.append(StringUtil.NEWLINE); buf.append("--> Headers:"); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } protected void appendHeaders(StringBuilder buf) { for (Map.Entry e: headers()) { buf.append(" "); buf.append(e.getKey()); buf.append(": "); buf.append(e.getValue()); buf.append(StringUtil.NEWLINE); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/DefaultSpdyPingFrame.java000066400000000000000000000026341225554127700331350ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdyPingFrame} implementation. */ public class DefaultSpdyPingFrame implements SpdyPingFrame { private int id; /** * Creates a new instance. * * @param id the unique ID of this frame */ public DefaultSpdyPingFrame(int id) { setId(id); } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append(StringUtil.NEWLINE); buf.append("--> ID = "); buf.append(getId()); return buf.toString(); } } DefaultSpdyRstStreamFrame.java000066400000000000000000000041011225554127700340740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdyRstStreamFrame} implementation. */ public class DefaultSpdyRstStreamFrame extends DefaultSpdyStreamFrame implements SpdyRstStreamFrame { private SpdyStreamStatus status; /** * Creates a new instance. * * @param streamId the Stream-ID of this frame * @param statusCode the Status code of this frame */ public DefaultSpdyRstStreamFrame(int streamId, int statusCode) { this(streamId, SpdyStreamStatus.valueOf(statusCode)); } /** * Creates a new instance. * * @param streamId the Stream-ID of this frame * @param status the status of this frame */ public DefaultSpdyRstStreamFrame(int streamId, SpdyStreamStatus status) { super(streamId); setStatus(status); } public SpdyStreamStatus getStatus() { return status; } public void setStatus(SpdyStreamStatus status) { this.status = status; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append(StringUtil.NEWLINE); buf.append("--> Stream-ID = "); buf.append(getStreamId()); buf.append(StringUtil.NEWLINE); buf.append("--> Status: "); buf.append(getStatus().toString()); return buf.toString(); } } DefaultSpdySettingsFrame.java000066400000000000000000000120701225554127700337540ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * The default {@link SpdySettingsFrame} implementation. */ public class DefaultSpdySettingsFrame implements SpdySettingsFrame { private boolean clear; private final Map settingsMap = new TreeMap(); public Set getIds() { return settingsMap.keySet(); } public boolean isSet(int id) { Integer key = id; return settingsMap.containsKey(key); } public int getValue(int id) { Integer key = id; if (settingsMap.containsKey(key)) { return settingsMap.get(key).getValue(); } else { return -1; } } public void setValue(int id, int value) { setValue(id, value, false, false); } public void setValue(int id, int value, boolean persistValue, boolean persisted) { if (id < 0 || id > SpdyCodecUtil.SPDY_SETTINGS_MAX_ID) { throw new IllegalArgumentException("Setting ID is not valid: " + id); } Integer key = id; if (settingsMap.containsKey(key)) { Setting setting = settingsMap.get(key); setting.setValue(value); setting.setPersist(persistValue); setting.setPersisted(persisted); } else { settingsMap.put(key, new Setting(value, persistValue, persisted)); } } public void removeValue(int id) { Integer key = id; if (settingsMap.containsKey(key)) { settingsMap.remove(key); } } public boolean isPersistValue(int id) { Integer key = id; if (settingsMap.containsKey(key)) { return settingsMap.get(key).isPersist(); } else { return false; } } public void setPersistValue(int id, boolean persistValue) { Integer key = id; if (settingsMap.containsKey(key)) { settingsMap.get(key).setPersist(persistValue); } } public boolean isPersisted(int id) { Integer key = id; if (settingsMap.containsKey(key)) { return settingsMap.get(key).isPersisted(); } else { return false; } } public void setPersisted(int id, boolean persisted) { Integer key = id; if (settingsMap.containsKey(key)) { settingsMap.get(key).setPersisted(persisted); } } public boolean clearPreviouslyPersistedSettings() { return clear; } public void setClearPreviouslyPersistedSettings(boolean clear) { this.clear = clear; } private Set> getSettings() { return settingsMap.entrySet(); } private void appendSettings(StringBuilder buf) { for (Map.Entry e: getSettings()) { Setting setting = e.getValue(); buf.append("--> "); buf.append(e.getKey().toString()); buf.append(':'); buf.append(setting.getValue()); buf.append(" (persist value: "); buf.append(setting.isPersist()); buf.append("; persisted: "); buf.append(setting.isPersisted()); buf.append(')'); buf.append(StringUtil.NEWLINE); } } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append(StringUtil.NEWLINE); appendSettings(buf); buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } private static final class Setting { private int value; private boolean persist; private boolean persisted; Setting(int value, boolean persist, boolean persisted) { this.value = value; this.persist = persist; this.persisted = persisted; } int getValue() { return value; } void setValue(int value) { this.value = value; } boolean isPersist() { return persist; } void setPersist(boolean persist) { this.persist = persist; } boolean isPersisted() { return persisted; } void setPersisted(boolean persisted) { this.persisted = persisted; } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/DefaultSpdyStreamFrame.java000066400000000000000000000027321225554127700334720ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * The default {@link SpdyStreamFrame} implementation. */ public abstract class DefaultSpdyStreamFrame implements SpdyStreamFrame { private int streamId; private boolean last; /** * Creates a new instance. * * @param streamId the Stream-ID of this frame */ protected DefaultSpdyStreamFrame(int streamId) { setStreamId(streamId); } public int getStreamId() { return streamId; } public void setStreamId(int streamId) { if (streamId <= 0) { throw new IllegalArgumentException( "Stream-ID must be positive: " + streamId); } this.streamId = streamId; } public boolean isLast() { return last; } public void setLast(boolean last) { this.last = last; } } DefaultSpdySynReplyFrame.java000066400000000000000000000032741225554127700337470ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdySynReplyFrame} implementation. */ public class DefaultSpdySynReplyFrame extends DefaultSpdyHeadersFrame implements SpdySynReplyFrame { /** * Creates a new instance. * * @param streamId the Stream-ID of this frame */ public DefaultSpdySynReplyFrame(int streamId) { super(streamId); } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(last: "); buf.append(isLast()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append("--> Stream-ID = "); buf.append(getStreamId()); buf.append(StringUtil.NEWLINE); buf.append("--> Headers:"); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } } DefaultSpdySynStreamFrame.java000066400000000000000000000066221225554127700341070ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdySynStreamFrame} implementation. */ public class DefaultSpdySynStreamFrame extends DefaultSpdyHeadersFrame implements SpdySynStreamFrame { private int associatedToStreamId; private byte priority; private boolean unidirectional; /** * Creates a new instance. * * @param streamId the Stream-ID of this frame * @param associatedToStreamId the Associated-To-Stream-ID of this frame * @param priority the priority of the stream */ public DefaultSpdySynStreamFrame( int streamId, int associatedToStreamId, byte priority) { super(streamId); setAssociatedToStreamId(associatedToStreamId); setPriority(priority); } public int getAssociatedToStreamId() { return associatedToStreamId; } public void setAssociatedToStreamId(int associatedToStreamId) { if (associatedToStreamId < 0) { throw new IllegalArgumentException( "Associated-To-Stream-ID cannot be negative: " + associatedToStreamId); } this.associatedToStreamId = associatedToStreamId; } public byte getPriority() { return priority; } public void setPriority(byte priority) { if (priority < 0 || priority > 7) { throw new IllegalArgumentException( "Priority must be between 0 and 7 inclusive: " + priority); } this.priority = priority; } public boolean isUnidirectional() { return unidirectional; } public void setUnidirectional(boolean unidirectional) { this.unidirectional = unidirectional; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append("(last: "); buf.append(isLast()); buf.append("; unidirectional: "); buf.append(isUnidirectional()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append("--> Stream-ID = "); buf.append(getStreamId()); buf.append(StringUtil.NEWLINE); if (associatedToStreamId != 0) { buf.append("--> Associated-To-Stream-ID = "); buf.append(getAssociatedToStreamId()); buf.append(StringUtil.NEWLINE); } buf.append("--> Priority = "); buf.append(getPriority()); buf.append(StringUtil.NEWLINE); buf.append("--> Headers:"); buf.append(StringUtil.NEWLINE); appendHeaders(buf); // Remove the last newline. buf.setLength(buf.length() - StringUtil.NEWLINE.length()); return buf.toString(); } } DefaultSpdyWindowUpdateFrame.java000066400000000000000000000045201225554127700345670ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.util.internal.StringUtil; /** * The default {@link SpdyWindowUpdateFrame} implementation. */ public class DefaultSpdyWindowUpdateFrame implements SpdyWindowUpdateFrame { private int streamId; private int deltaWindowSize; /** * Creates a new instance. * * @param streamId the Stream-ID of this frame * @param deltaWindowSize the Delta-Window-Size of this frame */ public DefaultSpdyWindowUpdateFrame(int streamId, int deltaWindowSize) { setStreamId(streamId); setDeltaWindowSize(deltaWindowSize); } public int getStreamId() { return streamId; } public void setStreamId(int streamId) { if (streamId < 0) { throw new IllegalArgumentException( "Stream-ID cannot be negative: " + streamId); } this.streamId = streamId; } public int getDeltaWindowSize() { return deltaWindowSize; } public void setDeltaWindowSize(int deltaWindowSize) { if (deltaWindowSize <= 0) { throw new IllegalArgumentException( "Delta-Window-Size must be positive: " + deltaWindowSize); } this.deltaWindowSize = deltaWindowSize; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append(StringUtil.NEWLINE); buf.append("--> Stream-ID = "); buf.append(getStreamId()); buf.append(StringUtil.NEWLINE); buf.append("--> Delta-Window-Size = "); buf.append(getDeltaWindowSize()); return buf.toString(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyCodecUtil.java000066400000000000000000000450711225554127700316350ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; final class SpdyCodecUtil { static final int SPDY_SESSION_STREAM_ID = 0; static final int SPDY_HEADER_TYPE_OFFSET = 2; static final int SPDY_HEADER_FLAGS_OFFSET = 4; static final int SPDY_HEADER_LENGTH_OFFSET = 5; static final int SPDY_HEADER_SIZE = 8; static final int SPDY_MAX_LENGTH = 0xFFFFFF; // Length is a 24-bit field static final byte SPDY_DATA_FLAG_FIN = 0x01; static final int SPDY_DATA_FRAME = 0; static final int SPDY_SYN_STREAM_FRAME = 1; static final int SPDY_SYN_REPLY_FRAME = 2; static final int SPDY_RST_STREAM_FRAME = 3; static final int SPDY_SETTINGS_FRAME = 4; static final int SPDY_PUSH_PROMISE_FRAME = 5; static final int SPDY_PING_FRAME = 6; static final int SPDY_GOAWAY_FRAME = 7; static final int SPDY_HEADERS_FRAME = 8; static final int SPDY_WINDOW_UPDATE_FRAME = 9; static final byte SPDY_FLAG_FIN = 0x01; static final byte SPDY_FLAG_UNIDIRECTIONAL = 0x02; static final byte SPDY_SETTINGS_CLEAR = 0x01; static final byte SPDY_SETTINGS_PERSIST_VALUE = 0x01; static final byte SPDY_SETTINGS_PERSISTED = 0x02; static final int SPDY_SETTINGS_MAX_ID = 0xFFFFFF; // ID is a 24-bit field static final int SPDY_MAX_NV_LENGTH = 0xFFFF; // Length is a 16-bit field // Zlib Dictionary static final byte[] SPDY_DICT = { 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - - 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - - 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t - 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e - 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e - 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t - 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - - 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - - 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - - 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - - 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - - 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - - 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h - 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - - 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - - 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f - 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - - 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - - 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a - 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - - 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - - 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r - 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e - 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g - 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a - 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - - 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t - 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - - 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e - 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 - 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e - 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t - 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v - 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u - 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - - 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t - 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 - 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - - 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 - }; private SpdyCodecUtil() { } /** * Reads a big-endian unsigned short integer from the buffer. */ static int getUnsignedShort(ChannelBuffer buf, int offset) { return (buf.getByte(offset) & 0xFF) << 8 | buf.getByte(offset + 1) & 0xFF; } /** * Reads a big-endian unsigned medium integer from the buffer. */ static int getUnsignedMedium(ChannelBuffer buf, int offset) { return (buf.getByte(offset) & 0xFF) << 16 | (buf.getByte(offset + 1) & 0xFF) << 8 | buf.getByte(offset + 2) & 0xFF; } /** * Reads a big-endian (31-bit) integer from the buffer. */ static int getUnsignedInt(ChannelBuffer buf, int offset) { return (buf.getByte(offset) & 0x7F) << 24 | (buf.getByte(offset + 1) & 0xFF) << 16 | (buf.getByte(offset + 2) & 0xFF) << 8 | buf.getByte(offset + 3) & 0xFF; } /** * Reads a big-endian signed integer from the buffer. */ static int getSignedInt(ChannelBuffer buf, int offset) { return (buf.getByte(offset) & 0xFF) << 24 | (buf.getByte(offset + 1) & 0xFF) << 16 | (buf.getByte(offset + 2) & 0xFF) << 8 | buf.getByte(offset + 3) & 0xFF; } /** * Returns {@code true} if ID is for a server initiated stream or ping. */ static boolean isServerId(int id) { // Server initiated streams and pings have even IDs return id % 2 == 0; } /** * Validate a SPDY header name. */ static void validateHeaderName(String name) { if (name == null) { throw new NullPointerException("name"); } if (name.length() == 0) { throw new IllegalArgumentException( "name cannot be length zero"); } // Since name may only contain ascii characters, for valid names // name.length() returns the number of bytes when UTF-8 encoded. if (name.length() > SPDY_MAX_NV_LENGTH) { throw new IllegalArgumentException( "name exceeds allowable length: " + name); } for (int i = 0; i < name.length(); i ++) { char c = name.charAt(i); if (c == 0) { throw new IllegalArgumentException( "name contains null character: " + name); } if (c > 127) { throw new IllegalArgumentException( "name contains non-ascii character: " + name); } } } /** * Validate a SPDY header value. Does not validate max length. */ static void validateHeaderValue(String value) { if (value == null) { throw new NullPointerException("value"); } for (int i = 0; i < value.length(); i ++) { char c = value.charAt(i); if (c == 0) { throw new IllegalArgumentException( "value contains null character: " + value); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyDataFrame.java000066400000000000000000000024331225554127700316010ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * A SPDY Protocol DATA Frame */ public interface SpdyDataFrame extends SpdyStreamFrame { /** * Returns the data payload of this frame. If there is no data payload * {@link ChannelBuffers#EMPTY_BUFFER} is returned. */ ChannelBuffer getData(); /** * Sets the data payload of this frame. If {@code null} is specified, * the data payload will be set to {@link ChannelBuffers#EMPTY_BUFFER}. * The data payload cannot exceed 16777215 bytes. */ void setData(ChannelBuffer data); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyFrame.java000066400000000000000000000013751225554127700310130ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol Frame */ public interface SpdyFrame { // Tag interface } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyFrameCodec.java000066400000000000000000000046021225554127700317450ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelUpstreamHandler; /** * A combination of {@link SpdyFrameDecoder} and {@link SpdyFrameEncoder}. * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyFrameDecoder * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyFrameEncoder */ public class SpdyFrameCodec implements ChannelUpstreamHandler, ChannelDownstreamHandler { private final SpdyFrameDecoder decoder; private final SpdyFrameEncoder encoder; /** * Creates a new instance with the specified {@code version} and * the default decoder and encoder options * ({@code maxChunkSize (8192)}, {@code maxHeaderSize (16384)}, * {@code compressionLevel (6)}, {@code windowBits (15)}, * and {@code memLevel (8)}). */ public SpdyFrameCodec(SpdyVersion version) { this(version, 8192, 16384, 6, 15, 8); } /** * Creates a new instance with the specified decoder and encoder options. */ public SpdyFrameCodec( SpdyVersion version, int maxChunkSize, int maxHeaderSize, int compressionLevel, int windowBits, int memLevel) { decoder = new SpdyFrameDecoder(version, maxChunkSize, maxHeaderSize); encoder = new SpdyFrameEncoder(version, compressionLevel, windowBits, memLevel); } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { decoder.handleUpstream(ctx, e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { encoder.handleDownstream(ctx, e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyFrameDecoder.java000066400000000000000000000423451225554127700323030ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.handler.codec.frame.FrameDecoder; /** * Decodes {@link ChannelBuffer}s into SPDY Frames. */ public class SpdyFrameDecoder extends FrameDecoder { private static final SpdyProtocolException INVALID_FRAME = new SpdyProtocolException("Received invalid frame"); private final int spdyVersion; private final int maxChunkSize; private final SpdyHeaderBlockDecoder headerBlockDecoder; private State state; private SpdySettingsFrame spdySettingsFrame; private SpdyHeadersFrame spdyHeadersFrame; // SPDY common header fields private byte flags; private int length; private int version; private int type; private int streamId; private enum State { READ_COMMON_HEADER, READ_CONTROL_FRAME, READ_SETTINGS_FRAME, READ_HEADER_BLOCK_FRAME, READ_HEADER_BLOCK, READ_DATA_FRAME, DISCARD_FRAME, FRAME_ERROR } /** * Creates a new instance with the specified {@code version} and the default * {@code maxChunkSize (8192)} and {@code maxHeaderSize (16384)}. */ public SpdyFrameDecoder(SpdyVersion spdyVersion) { this(spdyVersion, 8192, 16384); } /** * Creates a new instance with the specified parameters. */ public SpdyFrameDecoder(SpdyVersion spdyVersion, int maxChunkSize, int maxHeaderSize) { this(spdyVersion, maxChunkSize, SpdyHeaderBlockDecoder.newInstance(spdyVersion, maxHeaderSize)); } protected SpdyFrameDecoder( SpdyVersion spdyVersion, int maxChunkSize, SpdyHeaderBlockDecoder headerBlockDecoder) { super(false); if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } if (maxChunkSize <= 0) { throw new IllegalArgumentException( "maxChunkSize must be a positive integer: " + maxChunkSize); } this.spdyVersion = spdyVersion.getVersion(); this.maxChunkSize = maxChunkSize; this.headerBlockDecoder = headerBlockDecoder; state = State.READ_COMMON_HEADER; } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { switch(state) { case READ_COMMON_HEADER: state = readCommonHeader(buffer); if (state == State.FRAME_ERROR) { if (version != spdyVersion) { fireProtocolException(ctx, "Unsupported version: " + version); } else { fireInvalidFrameException(ctx); } } // FrameDecoders must consume data when producing frames // All length 0 frames must be generated now if (length == 0) { if (state == State.READ_DATA_FRAME) { SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId); spdyDataFrame.setLast((flags & SPDY_DATA_FLAG_FIN) != 0); state = State.READ_COMMON_HEADER; return spdyDataFrame; } // There are no length 0 control frames state = State.READ_COMMON_HEADER; } return null; case READ_CONTROL_FRAME: try { Object frame = readControlFrame(buffer); if (frame != null) { state = State.READ_COMMON_HEADER; } return frame; } catch (IllegalArgumentException e) { state = State.FRAME_ERROR; fireInvalidFrameException(ctx); } return null; case READ_SETTINGS_FRAME: if (spdySettingsFrame == null) { // Validate frame length against number of entries if (buffer.readableBytes() < 4) { return null; } int numEntries = getUnsignedInt(buffer, buffer.readerIndex()); buffer.skipBytes(4); length -= 4; // Each ID/Value entry is 8 bytes if ((length & 0x07) != 0 || length >> 3 != numEntries) { state = State.FRAME_ERROR; fireInvalidFrameException(ctx); return null; } spdySettingsFrame = new DefaultSpdySettingsFrame(); boolean clear = (flags & SPDY_SETTINGS_CLEAR) != 0; spdySettingsFrame.setClearPreviouslyPersistedSettings(clear); } int readableEntries = Math.min(buffer.readableBytes() >> 3, length >> 3); for (int i = 0; i < readableEntries; i ++) { byte ID_flags = buffer.getByte(buffer.readerIndex()); int ID = getUnsignedMedium(buffer, buffer.readerIndex() + 1); int value = getSignedInt(buffer, buffer.readerIndex() + 4); buffer.skipBytes(8); if (!spdySettingsFrame.isSet(ID)) { boolean persistVal = (ID_flags & SPDY_SETTINGS_PERSIST_VALUE) != 0; boolean persisted = (ID_flags & SPDY_SETTINGS_PERSISTED) != 0; spdySettingsFrame.setValue(ID, value, persistVal, persisted); } } length -= 8 * readableEntries; if (length == 0) { state = State.READ_COMMON_HEADER; Object frame = spdySettingsFrame; spdySettingsFrame = null; return frame; } return null; case READ_HEADER_BLOCK_FRAME: try { spdyHeadersFrame = readHeaderBlockFrame(buffer); if (spdyHeadersFrame != null) { if (length == 0) { state = State.READ_COMMON_HEADER; Object frame = spdyHeadersFrame; spdyHeadersFrame = null; return frame; } state = State.READ_HEADER_BLOCK; } return null; } catch (IllegalArgumentException e) { state = State.FRAME_ERROR; fireInvalidFrameException(ctx); return null; } case READ_HEADER_BLOCK: int compressedBytes = Math.min(buffer.readableBytes(), length); ChannelBuffer compressed = buffer.slice(buffer.readerIndex(), compressedBytes); try { headerBlockDecoder.decode(compressed, spdyHeadersFrame); } catch (Exception e) { state = State.FRAME_ERROR; spdyHeadersFrame = null; Channels.fireExceptionCaught(ctx, e); return null; } int readBytes = compressedBytes - compressed.readableBytes(); buffer.skipBytes(readBytes); length -= readBytes; if (spdyHeadersFrame != null && (spdyHeadersFrame.isInvalid() || spdyHeadersFrame.isTruncated())) { Object frame = spdyHeadersFrame; spdyHeadersFrame = null; if (length == 0) { headerBlockDecoder.reset(); state = State.READ_COMMON_HEADER; } return frame; } if (length == 0) { Object frame = spdyHeadersFrame; spdyHeadersFrame = null; headerBlockDecoder.reset(); state = State.READ_COMMON_HEADER; return frame; } return null; case READ_DATA_FRAME: if (streamId == 0) { state = State.FRAME_ERROR; fireProtocolException(ctx, "Received invalid data frame"); return null; } // Generate data frames that do not exceed maxChunkSize int dataLength = Math.min(maxChunkSize, length); // Wait until entire frame is readable if (buffer.readableBytes() < dataLength) { return null; } SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId); spdyDataFrame.setData(buffer.readBytes(dataLength)); length -= dataLength; if (length == 0) { spdyDataFrame.setLast((flags & SPDY_DATA_FLAG_FIN) != 0); state = State.READ_COMMON_HEADER; } return spdyDataFrame; case DISCARD_FRAME: int numBytes = Math.min(buffer.readableBytes(), length); buffer.skipBytes(numBytes); length -= numBytes; if (length == 0) { state = State.READ_COMMON_HEADER; } return null; case FRAME_ERROR: buffer.skipBytes(buffer.readableBytes()); return null; default: throw new Error("Shouldn't reach here."); } } private State readCommonHeader(ChannelBuffer buffer) { // Wait until entire header is readable if (buffer.readableBytes() < SPDY_HEADER_SIZE) { return State.READ_COMMON_HEADER; } int frameOffset = buffer.readerIndex(); int flagsOffset = frameOffset + SPDY_HEADER_FLAGS_OFFSET; int lengthOffset = frameOffset + SPDY_HEADER_LENGTH_OFFSET; buffer.skipBytes(SPDY_HEADER_SIZE); // Read common header fields boolean control = (buffer.getByte(frameOffset) & 0x80) != 0; flags = buffer.getByte(flagsOffset); length = getUnsignedMedium(buffer, lengthOffset); if (control) { // Decode control frame common header version = getUnsignedShort(buffer, frameOffset) & 0x7FFF; int typeOffset = frameOffset + SPDY_HEADER_TYPE_OFFSET; type = getUnsignedShort(buffer, typeOffset); streamId = 0; // Default to session Stream-ID } else { // Decode data frame common header version = spdyVersion; // Default to expected version type = SPDY_DATA_FRAME; streamId = getUnsignedInt(buffer, frameOffset); } // Check version first then validity if (version != spdyVersion || !isValidFrameHeader()) { return State.FRAME_ERROR; } // Make sure decoder will produce a frame or consume input State nextState; if (willGenerateFrame()) { switch (type) { case SPDY_DATA_FRAME: nextState = State.READ_DATA_FRAME; break; case SPDY_SYN_STREAM_FRAME: case SPDY_SYN_REPLY_FRAME: case SPDY_HEADERS_FRAME: nextState = State.READ_HEADER_BLOCK_FRAME; break; case SPDY_SETTINGS_FRAME: nextState = State.READ_SETTINGS_FRAME; break; default: nextState = State.READ_CONTROL_FRAME; } } else if (length != 0) { nextState = State.DISCARD_FRAME; } else { nextState = State.READ_COMMON_HEADER; } return nextState; } private Object readControlFrame(ChannelBuffer buffer) { int streamId; int statusCode; switch (type) { case SPDY_RST_STREAM_FRAME: if (buffer.readableBytes() < 8) { return null; } streamId = getUnsignedInt(buffer, buffer.readerIndex()); statusCode = getSignedInt(buffer, buffer.readerIndex() + 4); buffer.skipBytes(8); return new DefaultSpdyRstStreamFrame(streamId, statusCode); case SPDY_PING_FRAME: if (buffer.readableBytes() < 4) { return null; } int ID = getSignedInt(buffer, buffer.readerIndex()); buffer.skipBytes(4); return new DefaultSpdyPingFrame(ID); case SPDY_GOAWAY_FRAME: if (buffer.readableBytes() < 8) { return null; } int lastGoodStreamID = getUnsignedInt(buffer, buffer.readerIndex()); statusCode = getSignedInt(buffer, buffer.readerIndex() + 4); buffer.skipBytes(8); return new DefaultSpdyGoAwayFrame(lastGoodStreamID, statusCode); case SPDY_WINDOW_UPDATE_FRAME: if (buffer.readableBytes() < 8) { return null; } streamId = getUnsignedInt(buffer, buffer.readerIndex()); int deltaWindowSize = getUnsignedInt(buffer, buffer.readerIndex() + 4); buffer.skipBytes(8); return new DefaultSpdyWindowUpdateFrame(streamId, deltaWindowSize); default: throw new Error("Shouldn't reach here."); } } private SpdyHeadersFrame readHeaderBlockFrame(ChannelBuffer buffer) { int streamId; switch (type) { case SPDY_SYN_STREAM_FRAME: if (buffer.readableBytes() < 10) { return null; } int offset = buffer.readerIndex(); streamId = getUnsignedInt(buffer, offset); int associatedToStreamID = getUnsignedInt(buffer, offset + 4); byte priority = (byte) (buffer.getByte(offset + 8) >> 5 & 0x07); buffer.skipBytes(10); length -= 10; SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(streamId, associatedToStreamID, priority); spdySynStreamFrame.setLast((flags & SPDY_FLAG_FIN) != 0); spdySynStreamFrame.setUnidirectional((flags & SPDY_FLAG_UNIDIRECTIONAL) != 0); return spdySynStreamFrame; case SPDY_SYN_REPLY_FRAME: if (buffer.readableBytes() < 4) { return null; } streamId = getUnsignedInt(buffer, buffer.readerIndex()); buffer.skipBytes(4); length -= 4; SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId); spdySynReplyFrame.setLast((flags & SPDY_FLAG_FIN) != 0); return spdySynReplyFrame; case SPDY_HEADERS_FRAME: if (buffer.readableBytes() < 4) { return null; } streamId = getUnsignedInt(buffer, buffer.readerIndex()); buffer.skipBytes(4); length -= 4; SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamId); spdyHeadersFrame.setLast((flags & SPDY_FLAG_FIN) != 0); return spdyHeadersFrame; default: throw new Error("Shouldn't reach here."); } } private boolean isValidFrameHeader() { switch (type) { case SPDY_DATA_FRAME: return streamId != 0; case SPDY_SYN_STREAM_FRAME: return length >= 10; case SPDY_SYN_REPLY_FRAME: return length >= 4; case SPDY_RST_STREAM_FRAME: return flags == 0 && length == 8; case SPDY_SETTINGS_FRAME: return length >= 4; case SPDY_PING_FRAME: return length == 4; case SPDY_GOAWAY_FRAME: return length == 8; case SPDY_HEADERS_FRAME: return length >= 4; case SPDY_WINDOW_UPDATE_FRAME: return length == 8; default: return true; } } private boolean willGenerateFrame() { switch (type) { case SPDY_DATA_FRAME: case SPDY_SYN_STREAM_FRAME: case SPDY_SYN_REPLY_FRAME: case SPDY_RST_STREAM_FRAME: case SPDY_SETTINGS_FRAME: case SPDY_PING_FRAME: case SPDY_GOAWAY_FRAME: case SPDY_HEADERS_FRAME: case SPDY_WINDOW_UPDATE_FRAME: return true; default: return false; } } @Override protected void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { try { super.cleanup(ctx, e); } finally { headerBlockDecoder.end(); } } private static void fireInvalidFrameException(ChannelHandlerContext ctx) { Channels.fireExceptionCaught(ctx, INVALID_FRAME); } private static void fireProtocolException(ChannelHandlerContext ctx, String message) { Channels.fireExceptionCaught(ctx, new SpdyProtocolException(message)); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyFrameEncoder.java000066400000000000000000000260071225554127700323120ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import java.nio.ByteOrder; import java.util.Set; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; /** * Encodes a SPDY Frame into a {@link ChannelBuffer}. */ public class SpdyFrameEncoder implements ChannelDownstreamHandler { private final int version; private final SpdyHeaderBlockEncoder headerBlockEncoder; /** * Creates a new instance with the specified {@code version} and the * default {@code compressionLevel (6)}, {@code windowBits (15)}, * and {@code memLevel (8)}. */ public SpdyFrameEncoder(SpdyVersion spdyVersion) { this(spdyVersion, 6, 15, 8); } /** * Creates a new instance with the specified parameters. */ public SpdyFrameEncoder(SpdyVersion spdyVersion, int compressionLevel, int windowBits, int memLevel) { this(spdyVersion, SpdyHeaderBlockEncoder.newInstance( spdyVersion, compressionLevel, windowBits, memLevel)); } protected SpdyFrameEncoder(SpdyVersion spdyVersion, SpdyHeaderBlockEncoder headerBlockEncoder) { if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } version = spdyVersion.getVersion(); this.headerBlockEncoder = headerBlockEncoder; } public void handleDownstream( final ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (evt instanceof ChannelStateEvent) { ChannelStateEvent e = (ChannelStateEvent) evt; switch (e.getState()) { case OPEN: case CONNECTED: case BOUND: if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) { synchronized (headerBlockEncoder) { headerBlockEncoder.end(); } } } } if (!(evt instanceof MessageEvent)) { ctx.sendDownstream(evt); return; } final MessageEvent e = (MessageEvent) evt; Object msg = e.getMessage(); if (msg instanceof SpdyDataFrame) { SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; ChannelBuffer data = spdyDataFrame.getData(); byte flags = spdyDataFrame.isLast() ? SPDY_DATA_FLAG_FIN : 0; ChannelBuffer header = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE); header.writeInt(spdyDataFrame.getStreamId() & 0x7FFFFFFF); header.writeByte(flags); header.writeMedium(data.readableBytes()); ChannelBuffer frame = ChannelBuffers.wrappedBuffer(header, data); Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); return; } if (msg instanceof SpdySynStreamFrame) { synchronized (headerBlockEncoder) { SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; ChannelBuffer data = headerBlockEncoder.encode(spdySynStreamFrame); byte flags = spdySynStreamFrame.isLast() ? SPDY_FLAG_FIN : 0; if (spdySynStreamFrame.isUnidirectional()) { flags |= SPDY_FLAG_UNIDIRECTIONAL; } int headerBlockLength = data.readableBytes(); int length = 10 + headerBlockLength; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 10); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_SYN_STREAM_FRAME); frame.writeByte(flags); frame.writeMedium(length); frame.writeInt(spdySynStreamFrame.getStreamId()); frame.writeInt(spdySynStreamFrame.getAssociatedToStreamId()); frame.writeShort((spdySynStreamFrame.getPriority() & 0xFF) << 13); // Writes of compressed data must occur in order final ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(frame, data); Channels.write(ctx, e.getFuture(), buffer, e.getRemoteAddress()); } return; } if (msg instanceof SpdySynReplyFrame) { synchronized (headerBlockEncoder) { SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; ChannelBuffer data = headerBlockEncoder.encode(spdySynReplyFrame); byte flags = spdySynReplyFrame.isLast() ? SPDY_FLAG_FIN : 0; int headerBlockLength = data.readableBytes(); int length = 4 + headerBlockLength; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_SYN_REPLY_FRAME); frame.writeByte(flags); frame.writeMedium(length); frame.writeInt(spdySynReplyFrame.getStreamId()); // Writes of compressed data must occur in order final ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(frame, data); Channels.write(ctx, e.getFuture(), buffer, e.getRemoteAddress()); } return; } if (msg instanceof SpdyRstStreamFrame) { SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 8); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_RST_STREAM_FRAME); frame.writeInt(8); frame.writeInt(spdyRstStreamFrame.getStreamId()); frame.writeInt(spdyRstStreamFrame.getStatus().getCode()); Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); return; } if (msg instanceof SpdySettingsFrame) { SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; byte flags = spdySettingsFrame.clearPreviouslyPersistedSettings() ? SPDY_SETTINGS_CLEAR : 0; Set IDs = spdySettingsFrame.getIds(); int numEntries = IDs.size(); int length = 4 + numEntries * 8; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_SETTINGS_FRAME); frame.writeByte(flags); frame.writeMedium(length); frame.writeInt(numEntries); for (Integer id: IDs) { byte ID_flags = 0; if (spdySettingsFrame.isPersistValue(id)) { ID_flags |= SPDY_SETTINGS_PERSIST_VALUE; } if (spdySettingsFrame.isPersisted(id)) { ID_flags |= SPDY_SETTINGS_PERSISTED; } frame.writeByte(ID_flags); frame.writeMedium(id); frame.writeInt(spdySettingsFrame.getValue(id)); } Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); return; } if (msg instanceof SpdyPingFrame) { SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_PING_FRAME); frame.writeInt(4); frame.writeInt(spdyPingFrame.getId()); Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); return; } if (msg instanceof SpdyGoAwayFrame) { SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 8); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_GOAWAY_FRAME); frame.writeInt(8); frame.writeInt(spdyGoAwayFrame.getLastGoodStreamId()); frame.writeInt(spdyGoAwayFrame.getStatus().getCode()); Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); return; } if (msg instanceof SpdyHeadersFrame) { synchronized (headerBlockEncoder) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; ChannelBuffer data = headerBlockEncoder.encode(spdyHeadersFrame); byte flags = spdyHeadersFrame.isLast() ? SPDY_FLAG_FIN : 0; int headerBlockLength = data.readableBytes(); int length = 4 + headerBlockLength; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_HEADERS_FRAME); frame.writeByte(flags); frame.writeMedium(length); frame.writeInt(spdyHeadersFrame.getStreamId()); // Writes of compressed data must occur in order final ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(frame, data); Channels.write(ctx, e.getFuture(), buffer, e.getRemoteAddress()); } return; } if (msg instanceof SpdyWindowUpdateFrame) { SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg; ChannelBuffer frame = ChannelBuffers.buffer( ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 8); frame.writeShort(version | 0x8000); frame.writeShort(SPDY_WINDOW_UPDATE_FRAME); frame.writeInt(8); frame.writeInt(spdyWindowUpdateFrame.getStreamId()); frame.writeInt(spdyWindowUpdateFrame.getDeltaWindowSize()); Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); return; } // Unknown message type ctx.sendDownstream(evt); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyGoAwayFrame.java000066400000000000000000000023331225554127700321160ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol GOAWAY Frame */ public interface SpdyGoAwayFrame extends SpdyFrame { /** * Returns the Last-good-stream-ID of this frame. */ int getLastGoodStreamId(); /** * Sets the Last-good-stream-ID of this frame. The Last-good-stream-ID * cannot be negative. */ void setLastGoodStreamId(int lastGoodStreamId); /** * Returns the status of this frame. */ SpdySessionStatus getStatus(); /** * Sets the status of this frame. */ void setStatus(SpdySessionStatus status); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHeaderBlockDecoder.java000066400000000000000000000020751225554127700334100ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; abstract class SpdyHeaderBlockDecoder { static SpdyHeaderBlockDecoder newInstance(SpdyVersion spdyVersion, int maxHeaderSize) { return new SpdyHeaderBlockZlibDecoder(spdyVersion, maxHeaderSize); } abstract void decode(ChannelBuffer encoded, SpdyHeadersFrame frame) throws Exception; abstract void reset(); abstract void end(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHeaderBlockEncoder.java000066400000000000000000000025341225554127700334220ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.util.internal.DetectionUtil; abstract class SpdyHeaderBlockEncoder { static SpdyHeaderBlockEncoder newInstance( SpdyVersion spdyVersion, int compressionLevel, int windowBits, int memLevel) { if (DetectionUtil.javaVersion() >= 7) { return new SpdyHeaderBlockZlibEncoder( spdyVersion, compressionLevel); } else { return new SpdyHeaderBlockJZlibEncoder( spdyVersion, compressionLevel, windowBits, memLevel); } } abstract ChannelBuffer encode(SpdyHeadersFrame frame) throws Exception; abstract void end(); } SpdyHeaderBlockJZlibEncoder.java000066400000000000000000000105511225554127700342740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.compression.CompressionException; import org.jboss.netty.util.internal.jzlib.JZlib; import org.jboss.netty.util.internal.jzlib.ZStream; class SpdyHeaderBlockJZlibEncoder extends SpdyHeaderBlockRawEncoder { private final ZStream z = new ZStream(); private boolean finished; public SpdyHeaderBlockJZlibEncoder( SpdyVersion spdyVersion, int compressionLevel, int windowBits, int memLevel) { super(spdyVersion); if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } if (windowBits < 9 || windowBits > 15) { throw new IllegalArgumentException( "windowBits: " + windowBits + " (expected: 9-15)"); } if (memLevel < 1 || memLevel > 9) { throw new IllegalArgumentException( "memLevel: " + memLevel + " (expected: 1-9)"); } int resultCode = z.deflateInit( compressionLevel, windowBits, memLevel, JZlib.W_ZLIB); if (resultCode != JZlib.Z_OK) { throw new CompressionException( "failed to initialize an SPDY header block deflater: " + resultCode); } else { resultCode = z.deflateSetDictionary(SPDY_DICT, SPDY_DICT.length); if (resultCode != JZlib.Z_OK) { throw new CompressionException( "failed to set the SPDY dictionary: " + resultCode); } } } private void setInput(ChannelBuffer decompressed) { byte[] in = new byte[decompressed.readableBytes()]; decompressed.readBytes(in); z.next_in = in; z.next_in_index = 0; z.avail_in = in.length; } private void encode(ChannelBuffer compressed) { try { byte[] out = new byte[(int) Math.ceil(z.next_in.length * 1.001) + 12]; z.next_out = out; z.next_out_index = 0; z.avail_out = out.length; int resultCode = z.deflate(JZlib.Z_SYNC_FLUSH); if (resultCode != JZlib.Z_OK) { throw new CompressionException("compression failure: " + resultCode); } if (z.next_out_index != 0) { compressed.writeBytes(out, 0, z.next_out_index); } } finally { // Deference the external references explicitly to tell the VM that // the allocated byte arrays are temporary so that the call stack // can be utilized. // I'm not sure if the modern VMs do this optimization though. z.next_in = null; z.next_out = null; } } @Override public synchronized ChannelBuffer encode(SpdyHeadersFrame frame) throws Exception { if (frame == null) { throw new IllegalArgumentException("frame"); } if (finished) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer decompressed = super.encode(frame); if (decompressed.readableBytes() == 0) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer compressed = ChannelBuffers.dynamicBuffer(); setInput(decompressed); encode(compressed); return compressed; } @Override public synchronized void end() { if (finished) { return; } finished = true; z.deflateEnd(); z.next_in = null; z.next_out = null; } } SpdyHeaderBlockRawDecoder.java000066400000000000000000000133321225554127700340010ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder { private static final int LENGTH_FIELD_SIZE = 4; private final int version; private final int maxHeaderSize; // Header block decoding fields private int headerSize; private int numHeaders = -1; public SpdyHeaderBlockRawDecoder(SpdyVersion spdyVersion, int maxHeaderSize) { if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } this.version = spdyVersion.getVersion(); this.maxHeaderSize = maxHeaderSize; } private int readLengthField(ChannelBuffer buffer) { int length = getSignedInt(buffer, buffer.readerIndex()); buffer.skipBytes(LENGTH_FIELD_SIZE); return length; } @Override void decode(ChannelBuffer encoded, SpdyHeadersFrame frame) throws Exception { if (encoded == null) { throw new NullPointerException("encoded"); } if (frame == null) { throw new NullPointerException("frame"); } if (numHeaders == -1) { // Read number of Name/Value pairs if (encoded.readableBytes() < LENGTH_FIELD_SIZE) { return; } numHeaders = readLengthField(encoded); if (numHeaders < 0) { frame.setInvalid(); return; } } while (numHeaders > 0) { int headerSize = this.headerSize; encoded.markReaderIndex(); // Try to read length of name if (encoded.readableBytes() < LENGTH_FIELD_SIZE) { encoded.resetReaderIndex(); return; } int nameLength = readLengthField(encoded); // Recipients of a zero-length name must issue a stream error if (nameLength <= 0) { frame.setInvalid(); return; } headerSize += nameLength; if (headerSize > maxHeaderSize) { frame.setTruncated(); return; } // Try to read name if (encoded.readableBytes() < nameLength) { encoded.resetReaderIndex(); return; } byte[] nameBytes = new byte[nameLength]; encoded.readBytes(nameBytes); String name = new String(nameBytes, "UTF-8"); // Check for identically named headers if (frame.headers().contains(name)) { frame.setInvalid(); return; } // Try to read length of value if (encoded.readableBytes() < LENGTH_FIELD_SIZE) { encoded.resetReaderIndex(); return; } int valueLength = readLengthField(encoded); // Recipients of illegal value fields must issue a stream error if (valueLength < 0) { frame.setInvalid(); return; } // SPDY/3 allows zero-length (empty) header values if (valueLength == 0) { frame.headers().add(name, ""); numHeaders --; this.headerSize = headerSize; continue; } headerSize += valueLength; if (headerSize > maxHeaderSize) { frame.setTruncated(); return; } // Try to read value if (encoded.readableBytes() < valueLength) { encoded.resetReaderIndex(); return; } byte[] valueBytes = new byte[valueLength]; encoded.readBytes(valueBytes); // Add Name/Value pair to headers int index = 0; int offset = 0; while (index < valueLength) { while (index < valueBytes.length && valueBytes[index] != (byte) 0) { index ++; } if (index < valueBytes.length && valueBytes[index + 1] == (byte) 0) { // Received multiple, in-sequence NULL characters // Recipients of illegal value fields must issue a stream error frame.setInvalid(); return; } String value = new String(valueBytes, offset, index - offset, "UTF-8"); try { frame.headers().add(name, value); } catch (IllegalArgumentException e) { // Name contains NULL or non-ascii characters frame.setInvalid(); return; } index ++; offset = index; } numHeaders --; this.headerSize = headerSize; } } @Override void reset() { // Initialize header block decoding fields headerSize = 0; numHeaders = -1; } @Override void end() { } } SpdyHeaderBlockRawEncoder.java000066400000000000000000000063741225554127700340230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.nio.ByteOrder; import java.util.Set; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder { private final int version; public SpdyHeaderBlockRawEncoder(SpdyVersion spdyVersion) { if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } version = spdyVersion.getVersion(); } private void setLengthField(ChannelBuffer buffer, int writerIndex, int length) { buffer.setInt(writerIndex, length); } private void writeLengthField(ChannelBuffer buffer, int length) { buffer.writeInt(length); } @Override public ChannelBuffer encode(SpdyHeadersFrame headerFrame) throws Exception { Set names = headerFrame.headers().names(); int numHeaders = names.size(); if (numHeaders == 0) { return ChannelBuffers.EMPTY_BUFFER; } if (numHeaders > SPDY_MAX_NV_LENGTH) { throw new IllegalArgumentException( "header block contains too many headers"); } ChannelBuffer headerBlock = ChannelBuffers.dynamicBuffer( ByteOrder.BIG_ENDIAN, 256); writeLengthField(headerBlock, numHeaders); for (String name: names) { byte[] nameBytes = name.getBytes("UTF-8"); writeLengthField(headerBlock, nameBytes.length); headerBlock.writeBytes(nameBytes); int savedIndex = headerBlock.writerIndex(); int valueLength = 0; writeLengthField(headerBlock, valueLength); for (String value: headerFrame.headers().getAll(name)) { byte[] valueBytes = value.getBytes("UTF-8"); if (valueBytes.length > 0) { headerBlock.writeBytes(valueBytes); headerBlock.writeByte(0); valueLength += valueBytes.length + 1; } } if (valueLength != 0) { valueLength --; } if (valueLength > SPDY_MAX_NV_LENGTH) { throw new IllegalArgumentException( "header exceeds allowable length: " + name); } if (valueLength > 0) { setLengthField(headerBlock, savedIndex, valueLength); headerBlock.writerIndex(headerBlock.writerIndex() - 1); } } return headerBlock; } @Override void end() { } } SpdyHeaderBlockZlibDecoder.java000066400000000000000000000063531225554127700341550ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; import java.util.zip.DataFormatException; import java.util.zip.Inflater; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; final class SpdyHeaderBlockZlibDecoder extends SpdyHeaderBlockRawDecoder { private final Inflater decompressor = new Inflater(); private final ChannelBuffer decompressed = ChannelBuffers.buffer(4096); public SpdyHeaderBlockZlibDecoder(SpdyVersion spdyVersion, int maxHeaderSize) { super(spdyVersion, maxHeaderSize); } @Override void decode(ChannelBuffer encoded, SpdyHeadersFrame frame) throws Exception { int len = setInput(encoded); int numBytes; do { numBytes = decompress(frame); } while (!decompressed.readable() && numBytes > 0); if (decompressor.getRemaining() != 0) { throw new SpdyProtocolException("client sent extra data beyond headers"); } encoded.skipBytes(len); } private int setInput(ChannelBuffer compressed) { int len = compressed.readableBytes(); if (compressed.hasArray()) { decompressor.setInput(compressed.array(), compressed.arrayOffset() + compressed.readerIndex(), len); } else { byte[] in = new byte[len]; compressed.getBytes(compressed.readerIndex(), in); decompressor.setInput(in, 0, in.length); } return len; } private int decompress(SpdyHeadersFrame frame) throws Exception { byte[] out = decompressed.array(); int off = decompressed.arrayOffset() + decompressed.writerIndex(); try { int numBytes = decompressor.inflate(out, off, decompressed.writableBytes()); if (numBytes == 0 && decompressor.needsDictionary()) { decompressor.setDictionary(SPDY_DICT); numBytes = decompressor.inflate(out, off, decompressed.writableBytes()); } if (frame != null) { decompressed.writerIndex(decompressed.writerIndex() + numBytes); super.decode(decompressed, frame); decompressed.discardReadBytes(); } return numBytes; } catch (DataFormatException e) { throw new SpdyProtocolException("Received invalid header block", e); } } @Override void reset() { decompressed.clear(); super.reset(); } @Override public void end() { decompressed.clear(); decompressor.end(); super.end(); } } SpdyHeaderBlockZlibEncoder.java000066400000000000000000000066371225554127700341740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; import java.util.zip.Deflater; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; class SpdyHeaderBlockZlibEncoder extends SpdyHeaderBlockRawEncoder { private final Deflater compressor; private boolean finished; public SpdyHeaderBlockZlibEncoder(SpdyVersion spdyVersion, int compressionLevel) { super(spdyVersion); if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } compressor = new Deflater(compressionLevel); compressor.setDictionary(SPDY_DICT); } private int setInput(ChannelBuffer decompressed) { int len = decompressed.readableBytes(); if (decompressed.hasArray()) { compressor.setInput(decompressed.array(), decompressed.arrayOffset() + decompressed.readerIndex(), len); } else { byte[] in = new byte[len]; decompressed.getBytes(decompressed.readerIndex(), in); compressor.setInput(in, 0, in.length); } return len; } private void encode(ChannelBuffer compressed) { while (compressInto(compressed)) { // Although unlikely, it's possible that the compressed size is larger than the decompressed size compressed.ensureWritableBytes(compressed.capacity() << 1); } } private boolean compressInto(ChannelBuffer compressed) { byte[] out = compressed.array(); int off = compressed.arrayOffset() + compressed.writerIndex(); int toWrite = compressed.writableBytes(); int numBytes = compressor.deflate(out, off, toWrite, Deflater.SYNC_FLUSH); compressed.writerIndex(compressed.writerIndex() + numBytes); return numBytes == toWrite; } @Override public synchronized ChannelBuffer encode(SpdyHeadersFrame frame) throws Exception { if (frame == null) { throw new IllegalArgumentException("frame"); } if (finished) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer decompressed = super.encode(frame); if (decompressed.readableBytes() == 0) { return ChannelBuffers.EMPTY_BUFFER; } ChannelBuffer compressed = ChannelBuffers.dynamicBuffer(decompressed.readableBytes()); int len = setInput(decompressed); encode(compressed); decompressed.skipBytes(len); return compressed; } @Override public synchronized void end() { if (finished) { return; } finished = true; compressor.end(); super.end(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHeaders.java000066400000000000000000000305251225554127700313330ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Provides the constants for the standard SPDY HTTP header names and commonly * used utility methods that access a {@link SpdyHeadersFrame}. */ public abstract class SpdyHeaders implements Iterable> { public static final SpdyHeaders EMPTY_HEADERS = new SpdyHeaders() { @Override public List getAll(String name) { return Collections.emptyList(); } @Override public List> entries() { return Collections.emptyList(); } @Override public boolean contains(String name) { return false; } @Override public boolean isEmpty() { return true; } @Override public Set names() { return Collections.emptySet(); } @Override public SpdyHeaders add(String name, Object value) { throw new UnsupportedOperationException("read only"); } @Override public SpdyHeaders add(String name, Iterable values) { throw new UnsupportedOperationException("read only"); } @Override public SpdyHeaders set(String name, Object value) { throw new UnsupportedOperationException("read only"); } @Override public SpdyHeaders set(String name, Iterable values) { throw new UnsupportedOperationException("read only"); } @Override public SpdyHeaders remove(String name) { throw new UnsupportedOperationException("read only"); } @Override public SpdyHeaders clear() { throw new UnsupportedOperationException("read only"); } @Override public Iterator> iterator() { return entries().iterator(); } @Override public String get(String name) { return null; } }; /** * SPDY HTTP header names */ public static final class HttpNames { /** * {@code ":host"} */ public static final String HOST = ":host"; /** * {@code ":method"} */ public static final String METHOD = ":method"; /** * {@code ":path"} */ public static final String PATH = ":path"; /** * {@code ":scheme"} */ public static final String SCHEME = ":scheme"; /** * {@code ":status"} */ public static final String STATUS = ":status"; /** * {@code ":version"} */ public static final String VERSION = ":version"; private HttpNames() { } } /** * Returns the header value with the specified header name. If there are * more than one header value for the specified header name, the first * value is returned. * * @return the header value or {@code null} if there is no such header */ public static String getHeader(SpdyHeadersFrame frame, String name) { return frame.headers().get(name); } /** * Returns the header value with the specified header name. If there are * more than one header value for the specified header name, the first * value is returned. * * @return the header value or the {@code defaultValue} if there is no such * header */ public static String getHeader(SpdyHeadersFrame frame, String name, String defaultValue) { String value = frame.headers().get(name); if (value == null) { return defaultValue; } return value; } /** * Sets a new header with the specified name and value. If there is an * existing header with the same name, the existing header is removed. */ public static void setHeader(SpdyHeadersFrame frame, String name, Object value) { frame.headers().set(name, value); } /** * Sets a new header with the specified name and values. If there is an * existing header with the same name, the existing header is removed. */ public static void setHeader(SpdyHeadersFrame frame, String name, Iterable values) { frame.headers().set(name, values); } /** * Adds a new header with the specified name and value. */ public static void addHeader(SpdyHeadersFrame frame, String name, Object value) { frame.headers().add(name, value); } /** * Removes the SPDY host header. */ public static void removeHost(SpdyHeadersFrame frame) { frame.headers().remove(HttpNames.HOST); } /** * Returns the SPDY host header. */ public static String getHost(SpdyHeadersFrame frame) { return frame.headers().get(HttpNames.HOST); } /** * Set the SPDY host header. */ public static void setHost(SpdyHeadersFrame frame, String host) { frame.headers().set(HttpNames.HOST, host); } /** * Removes the HTTP method header. */ public static void removeMethod(int spdyVersion, SpdyHeadersFrame frame) { frame.headers().remove(HttpNames.METHOD); } /** * Returns the {@link HttpMethod} represented by the HTTP method header. */ public static HttpMethod getMethod(int spdyVersion, SpdyHeadersFrame frame) { try { return HttpMethod.valueOf(frame.headers().get(HttpNames.METHOD)); } catch (Exception e) { return null; } } /** * Sets the HTTP method header. */ public static void setMethod(int spdyVersion, SpdyHeadersFrame frame, HttpMethod method) { frame.headers().set(HttpNames.METHOD, method.getName()); } /** * Removes the URL scheme header. */ public static void removeScheme(int spdyVersion, SpdyHeadersFrame frame) { frame.headers().remove(HttpNames.SCHEME); } /** * Returns the value of the URL scheme header. */ public static String getScheme(int spdyVersion, SpdyHeadersFrame frame) { return frame.headers().get(HttpNames.SCHEME); } /** * Sets the URL scheme header. */ public static void setScheme(int spdyVersion, SpdyHeadersFrame frame, String scheme) { frame.headers().set(HttpNames.SCHEME, scheme); } /** * Removes the HTTP response status header. */ public static void removeStatus(int spdyVersion, SpdyHeadersFrame frame) { frame.headers().remove(HttpNames.STATUS); } /** * Returns the {@link HttpResponseStatus} represented by the HTTP response status header. */ public static HttpResponseStatus getStatus(int spdyVersion, SpdyHeadersFrame frame) { try { String status = frame.headers().get(HttpNames.STATUS); int space = status.indexOf(' '); if (space == -1) { return HttpResponseStatus.valueOf(Integer.parseInt(status)); } else { int code = Integer.parseInt(status.substring(0, space)); String reasonPhrase = status.substring(space + 1); HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(code); if (responseStatus.getReasonPhrase().equals(reasonPhrase)) { return responseStatus; } else { return new HttpResponseStatus(code, reasonPhrase); } } } catch (Exception e) { return null; } } /** * Sets the HTTP response status header. */ public static void setStatus(int spdyVersion, SpdyHeadersFrame frame, HttpResponseStatus status) { frame.headers().set(HttpNames.STATUS, status.toString()); } /** * Removes the URL path header. */ public static void removeUrl(int spdyVersion, SpdyHeadersFrame frame) { frame.headers().remove(HttpNames.PATH); } /** * Returns the value of the URL path header. */ public static String getUrl(int spdyVersion, SpdyHeadersFrame frame) { return frame.headers().get(HttpNames.PATH); } /** * Sets the URL path header. */ public static void setUrl(int spdyVersion, SpdyHeadersFrame frame, String path) { frame.headers().set(HttpNames.PATH, path); } /** * Removes the HTTP version header. */ public static void removeVersion(int spdyVersion, SpdyHeadersFrame frame) { frame.headers().remove(HttpNames.VERSION); } /** * Returns the {@link HttpVersion} represented by the HTTP version header. */ public static HttpVersion getVersion(int spdyVersion, SpdyHeadersFrame frame) { try { return HttpVersion.valueOf(frame.headers().get(HttpNames.VERSION)); } catch (Exception e) { return null; } } /** * Sets the HTTP version header. */ public static void setVersion(int spdyVersion, SpdyHeadersFrame frame, HttpVersion httpVersion) { frame.headers().set(HttpNames.VERSION, httpVersion.getText()); } @Override public Iterator> iterator() { return entries().iterator(); } /** * Returns the header value with the specified header name. If there is * more than one header value for the specified header name, the first * value is returned. * * @return the header value or {@code null} if there is no such header */ public abstract String get(String name); /** * Returns the header values with the specified header name. * * @return the {@link List} of header values. An empty list if there is no * such header. */ public abstract List getAll(String name); /** * Returns all header names and values that this frame contains. * * @return the {@link List} of the header name-value pairs. An empty list * if there is no header in this message. */ public abstract List> entries(); /** * Returns {@code true} if and only if there is a header with the specified * header name. */ public abstract boolean contains(String name); /** * Returns the {@link Set} of all header names that this frame contains. */ public abstract Set names(); /** * Adds a new header with the specified name and value. */ public abstract SpdyHeaders add(String name, Object value); /** * Adds a new header with the specified name and values. If there is an * existing header with the same name, the existing header is removed. */ public abstract SpdyHeaders add(String name, Iterable values); /** * Sets a new header with the specified name and value. If there is an * existing header with the same name, the existing header is removed. */ public abstract SpdyHeaders set(String name, Object value); /** * Sets a new header with the specified name and values. If there is an * existing header with the same name, the existing header is removed. */ public abstract SpdyHeaders set(String name, Iterable values); /** * Removes the header with the specified name. */ public abstract SpdyHeaders remove(String name); /** * Removes all headers from this frame. */ public abstract SpdyHeaders clear(); /** * Checks if no header exists. */ public abstract boolean isEmpty(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHeadersFrame.java000066400000000000000000000053351225554127700323070ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.List; import java.util.Map; import java.util.Set; /** * A SPDY Protocol HEADERS Frame */ public interface SpdyHeadersFrame extends SpdyStreamFrame { /** * Returns {@code true} if this header block is invalid. * A RST_STREAM frame with code PROTOCOL_ERROR should be sent. */ boolean isInvalid(); /** * Marks this header block as invalid. */ void setInvalid(); /** * Returns {@code true} if this header block has been truncated due to * length restrictions. */ boolean isTruncated(); /** * Mark this header block as truncated. */ void setTruncated(); /** * Returns the {@link SpdyHeaders}. */ SpdyHeaders headers(); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated String getHeader(String name); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated List getHeaders(String name); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated List> getHeaders(); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated boolean containsHeader(String name); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated Set getHeaderNames(); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated void addHeader(String name, Object value); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated void setHeader(String name, Object value); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated void setHeader(String name, Iterable values); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated void removeHeader(String name); /** * @deprecated Use {@link SpdyHeaders#headers()} instead. */ @Deprecated void clearHeaders(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHttpCodec.java000066400000000000000000000035071225554127700316350ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelUpstreamHandler; /** * A combination of {@link SpdyHttpDecoder} and {@link SpdyHttpEncoder} * @apiviz.has org.jboss.netty.handler.codec.sdpy.SpdyHttpDecoder * @apiviz.has org.jboss.netty.handler.codec.spdy.SpdyHttpEncoder */ public class SpdyHttpCodec implements ChannelUpstreamHandler, ChannelDownstreamHandler { private final SpdyHttpDecoder decoder; private final SpdyHttpEncoder encoder; /** * Creates a new instance with the specified decoder options. */ public SpdyHttpCodec(SpdyVersion version, int maxContentLength) { decoder = new SpdyHttpDecoder(version, maxContentLength); encoder = new SpdyHttpEncoder(version); } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { decoder.handleUpstream(ctx, e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { encoder.handleDownstream(ctx, e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHttpDecoder.java000066400000000000000000000374421225554127700321720ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; import java.util.HashMap; import java.util.Map; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; /** * Decodes {@link SpdySynStreamFrame}s, {@link SpdySynReplyFrame}s, * and {@link SpdyDataFrame}s into {@link HttpRequest}s and {@link HttpResponse}s. */ public class SpdyHttpDecoder extends OneToOneDecoder { private final int spdyVersion; private final int maxContentLength; private final Map messageMap; /** * Creates a new instance. * * @param spdyVersion the protocol version * @param maxContentLength the maximum length of the message content. * If the length of the message content exceeds this value, * a {@link TooLongFrameException} will be raised. */ public SpdyHttpDecoder(SpdyVersion spdyVersion, int maxContentLength) { this(spdyVersion, maxContentLength, new HashMap()); } /** * Creates a new instance with the specified parameters. * * @param spdyVersion the protocol version * @param maxContentLength the maximum length of the message content. * If the length of the message content exceeds this value, * a {@link TooLongFrameException} will be raised. * @param messageMap the {@link Map} used to hold partially received messages. */ protected SpdyHttpDecoder(SpdyVersion spdyVersion, int maxContentLength, Map messageMap) { if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } if (maxContentLength <= 0) { throw new IllegalArgumentException( "maxContentLength must be a positive integer: " + maxContentLength); } this.spdyVersion = spdyVersion.getVersion(); this.maxContentLength = maxContentLength; this.messageMap = messageMap; } protected HttpMessage putMessage(int streamId, HttpMessage message) { return messageMap.put(streamId, message); } protected HttpMessage getMessage(int streamId) { return messageMap.get(streamId); } protected HttpMessage removeMessage(int streamId) { return messageMap.remove(streamId); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof SpdySynStreamFrame) { // HTTP requests/responses are mapped one-to-one to SPDY streams. SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; int streamId = spdySynStreamFrame.getStreamId(); if (isServerId(streamId)) { // SYN_STREAM frames initiated by the server are pushed resources int associatedToStreamId = spdySynStreamFrame.getAssociatedToStreamId(); // If a client receives a SYN_STREAM with an Associated-To-Stream-ID of 0 // it must reply with a RST_STREAM with error code INVALID_STREAM if (associatedToStreamId == 0) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INVALID_STREAM); Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame); } String URL = SpdyHeaders.getUrl(spdyVersion, spdySynStreamFrame); // If a client receives a SYN_STREAM without a 'url' header // it must reply with a RST_STREAM with error code PROTOCOL_ERROR if (URL == null) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR); Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame); } // If a client receives a response with a truncated header block, // reply with a RST_STREAM with error code INTERNAL_ERROR. if (spdySynStreamFrame.isTruncated()) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INTERNAL_ERROR); Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame); } try { HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynStreamFrame); // Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers SpdyHttpHeaders.setStreamId(httpResponse, streamId); SpdyHttpHeaders.setAssociatedToStreamId(httpResponse, associatedToStreamId); SpdyHttpHeaders.setPriority(httpResponse, spdySynStreamFrame.getPriority()); SpdyHttpHeaders.setUrl(httpResponse, URL); if (spdySynStreamFrame.isLast()) { HttpHeaders.setContentLength(httpResponse, 0); return httpResponse; } else { // Response body will follow in a series of Data Frames putMessage(streamId, httpResponse); } } catch (Exception e) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR); Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame); } } else { // SYN_STREAM frames initiated by the client are HTTP requests // If a client sends a request with a truncated header block, the server must // reply with a HTTP 431 REQUEST HEADER FIELDS TOO LARGE reply. if (spdySynStreamFrame.isTruncated()) { SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId); spdySynReplyFrame.setLast(true); SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE); SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, HttpVersion.HTTP_1_0); Channels.write(ctx, Channels.future(channel), spdySynReplyFrame); } try { HttpRequest httpRequest = createHttpRequest(spdyVersion, spdySynStreamFrame); // Set the Stream-ID as a header SpdyHttpHeaders.setStreamId(httpRequest, streamId); if (spdySynStreamFrame.isLast()) { return httpRequest; } else { // Request body will follow in a series of Data Frames putMessage(streamId, httpRequest); } } catch (Exception e) { // If a client sends a SYN_STREAM without all of the method, url (host and path), // scheme, and version headers the server must reply with a HTTP 400 BAD REQUEST reply. // Also sends HTTP 400 BAD REQUEST reply if header name/value pairs are invalid SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId); spdySynReplyFrame.setLast(true); SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, HttpResponseStatus.BAD_REQUEST); SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, HttpVersion.HTTP_1_0); Channels.write(ctx, Channels.future(channel), spdySynReplyFrame); } } } else if (msg instanceof SpdySynReplyFrame) { SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; int streamId = spdySynReplyFrame.getStreamId(); // If a client receives a SYN_REPLY with a truncated header block, // reply with a RST_STREAM frame with error code INTERNAL_ERROR. if (spdySynReplyFrame.isTruncated()) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INTERNAL_ERROR); Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame); } try { HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynReplyFrame); // Set the Stream-ID as a header SpdyHttpHeaders.setStreamId(httpResponse, streamId); if (spdySynReplyFrame.isLast()) { HttpHeaders.setContentLength(httpResponse, 0); return httpResponse; } else { // Response body will follow in a series of Data Frames putMessage(streamId, httpResponse); } } catch (Exception e) { // If a client receives a SYN_REPLY without valid status and version headers // the client must reply with a RST_STREAM frame indicating a PROTOCOL_ERROR SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR); Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame); } } else if (msg instanceof SpdyHeadersFrame) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; int streamId = spdyHeadersFrame.getStreamId(); HttpMessage httpMessage = getMessage(streamId); // If message is not in map discard HEADERS frame. if (httpMessage == null) { return null; } // Ignore trailers in a truncated HEADERS frame. if (!spdyHeadersFrame.isTruncated()) { for (Map.Entry e : spdyHeadersFrame.headers()) { httpMessage.headers().add(e.getKey(), e.getValue()); } } if (spdyHeadersFrame.isLast()) { HttpHeaders.setContentLength(httpMessage, httpMessage.getContent().readableBytes()); removeMessage(streamId); return httpMessage; } } else if (msg instanceof SpdyDataFrame) { SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; int streamId = spdyDataFrame.getStreamId(); HttpMessage httpMessage = getMessage(streamId); // If message is not in map discard Data Frame. if (httpMessage == null) { return null; } ChannelBuffer content = httpMessage.getContent(); if (content.readableBytes() > maxContentLength - spdyDataFrame.getData().readableBytes()) { removeMessage(streamId); throw new TooLongFrameException( "HTTP content length exceeded " + maxContentLength + " bytes."); } if (content == ChannelBuffers.EMPTY_BUFFER) { content = ChannelBuffers.dynamicBuffer(channel.getConfig().getBufferFactory()); content.writeBytes(spdyDataFrame.getData()); httpMessage.setContent(content); } else { content.writeBytes(spdyDataFrame.getData()); } if (spdyDataFrame.isLast()) { HttpHeaders.setContentLength(httpMessage, content.readableBytes()); removeMessage(streamId); return httpMessage; } } else if (msg instanceof SpdyRstStreamFrame) { SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; int streamId = spdyRstStreamFrame.getStreamId(); removeMessage(streamId); } return null; } private static HttpRequest createHttpRequest(int spdyVersion, SpdyHeadersFrame requestFrame) throws Exception { // Create the first line of the request from the name/value pairs HttpMethod method = SpdyHeaders.getMethod(spdyVersion, requestFrame); String url = SpdyHeaders.getUrl(spdyVersion, requestFrame); HttpVersion httpVersion = SpdyHeaders.getVersion(spdyVersion, requestFrame); SpdyHeaders.removeMethod(spdyVersion, requestFrame); SpdyHeaders.removeUrl(spdyVersion, requestFrame); SpdyHeaders.removeVersion(spdyVersion, requestFrame); HttpRequest httpRequest = new DefaultHttpRequest(httpVersion, method, url); // Remove the scheme header SpdyHeaders.removeScheme(spdyVersion, requestFrame); if (spdyVersion >= 3) { // Replace the SPDY host header with the HTTP host header String host = SpdyHeaders.getHost(requestFrame); SpdyHeaders.removeHost(requestFrame); HttpHeaders.setHost(httpRequest, host); } for (Map.Entry e: requestFrame.headers()) { httpRequest.headers().add(e.getKey(), e.getValue()); } // The Connection and Keep-Alive headers are no longer valid HttpHeaders.setKeepAlive(httpRequest, true); // Transfer-Encoding header is not valid httpRequest.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); return httpRequest; } private static HttpResponse createHttpResponse(int spdyVersion, SpdyHeadersFrame responseFrame) throws Exception { // Create the first line of the response from the name/value pairs HttpResponseStatus status = SpdyHeaders.getStatus(spdyVersion, responseFrame); HttpVersion version = SpdyHeaders.getVersion(spdyVersion, responseFrame); SpdyHeaders.removeStatus(spdyVersion, responseFrame); SpdyHeaders.removeVersion(spdyVersion, responseFrame); HttpResponse httpResponse = new DefaultHttpResponse(version, status); for (Map.Entry e: responseFrame.headers()) { httpResponse.headers().add(e.getKey(), e.getValue()); } // The Connection and Keep-Alive headers are no longer valid HttpHeaders.setKeepAlive(httpResponse, true); // Transfer-Encoding header is not valid httpResponse.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); httpResponse.headers().remove(HttpHeaders.Names.TRAILER); return httpResponse; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHttpEncoder.java000066400000000000000000000363611225554127700322030ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.DownstreamMessageEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpChunkTrailer; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import java.net.SocketAddress; import java.util.List; import java.util.Map; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; /** * Encodes {@link HttpRequest}s, {@link HttpResponse}s, and {@link HttpChunk}s * into {@link SpdySynStreamFrame}s and {@link SpdySynReplyFrame}s. * *

Request Annotations

* * SPDY specific headers must be added to {@link HttpRequest}s: * * * * * * * * * * * * *
Header NameHeader Value
{@code "X-SPDY-Stream-ID"}The Stream-ID for this request. * Stream-IDs must be odd, positive integers, and must increase monotonically.
{@code "X-SPDY-Priority"}The priority value for this request. * The priority should be between 0 and 7 inclusive. * 0 represents the highest priority and 7 represents the lowest. * This header is optional and defaults to 0.
* *

Response Annotations

* * SPDY specific headers must be added to {@link HttpResponse}s: * * * * * * * * *
Header NameHeader Value
{@code "X-SPDY-Stream-ID"}The Stream-ID of the request corresponding to this response.
* *

Pushed Resource Annotations

* * SPDY specific headers must be added to pushed {@link HttpResponse}s: * * * * * * * * * * * * * * * * * * * * *
Header NameHeader Value
{@code "X-SPDY-Stream-ID"}The Stream-ID for this resource. * Stream-IDs must be even, positive integers, and must increase monotonically.
{@code "X-SPDY-Associated-To-Stream-ID"}The Stream-ID of the request that initiated this pushed resource.
{@code "X-SPDY-Priority"}The priority value for this resource. * The priority should be between 0 and 7 inclusive. * 0 represents the highest priority and 7 represents the lowest. * This header is optional and defaults to 0.
{@code "X-SPDY-URL"}The absolute path for the resource being pushed.
* *

Required Annotations

* * SPDY requires that all Requests and Pushed Resources contain * an HTTP "Host" header. * *

Optional Annotations

* * Requests and Pushed Resources must contain a SPDY scheme header. * This can be set via the {@code "X-SPDY-Scheme"} header but otherwise * defaults to "https" as that is the most common SPDY deployment. * *

Chunked Content

* * This encoder associates all {@link HttpChunk}s that it receives * with the most recently received 'chunked' {@link HttpRequest} * or {@link HttpResponse}. * *

Pushed Resources

* * All pushed resources should be sent before sending the response * that corresponds to the initial request. */ public class SpdyHttpEncoder implements ChannelDownstreamHandler { private final int spdyVersion; private volatile int currentStreamId; /** * Creates a new instance. * * @param spdyVersion the protocol version */ public SpdyHttpEncoder(SpdyVersion spdyVersion) { if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } this.spdyVersion = spdyVersion.getVersion(); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (!(evt instanceof MessageEvent)) { ctx.sendDownstream(evt); return; } MessageEvent e = (MessageEvent) evt; Object msg = e.getMessage(); if (msg instanceof HttpRequest) { HttpRequest httpRequest = (HttpRequest) msg; SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpRequest); currentStreamId = spdySynStreamFrame.getStreamId(); ChannelFuture future = getMessageFuture(ctx, e, currentStreamId, httpRequest); Channels.write(ctx, future, spdySynStreamFrame, e.getRemoteAddress()); } else if (msg instanceof HttpResponse) { HttpResponse httpResponse = (HttpResponse) msg; if (httpResponse.headers().contains(SpdyHttpHeaders.Names.ASSOCIATED_TO_STREAM_ID)) { SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpResponse); currentStreamId = spdySynStreamFrame.getStreamId(); ChannelFuture future = getMessageFuture(ctx, e, currentStreamId, httpResponse); Channels.write(ctx, future, spdySynStreamFrame, e.getRemoteAddress()); } else { SpdySynReplyFrame spdySynReplyFrame = createSynReplyFrame(httpResponse); currentStreamId = spdySynReplyFrame.getStreamId(); ChannelFuture future = getMessageFuture(ctx, e, currentStreamId, httpResponse); Channels.write(ctx, future, spdySynReplyFrame, e.getRemoteAddress()); } } else if (msg instanceof HttpChunk) { HttpChunk chunk = (HttpChunk) msg; writeChunk(ctx, e.getFuture(), currentStreamId, chunk, e.getRemoteAddress()); } else { // Unknown message type ctx.sendDownstream(evt); } } /** * Writes an HTTP chunk downstream as one or more SPDY frames. */ protected void writeChunk( ChannelHandlerContext ctx, ChannelFuture future, int streamId, HttpChunk chunk, SocketAddress remoteAddress) { if (chunk.isLast()) { if (chunk instanceof HttpChunkTrailer) { HttpChunkTrailer trailer = (HttpChunkTrailer) chunk; HttpHeaders trailers = trailer.trailingHeaders(); if (trailers.isEmpty()) { SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId); spdyDataFrame.setLast(true); Channels.write(ctx, future, spdyDataFrame, remoteAddress); } else { // Create SPDY HEADERS frame out of trailers SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamId); spdyHeadersFrame.setLast(true); for (Map.Entry entry: trailers) { spdyHeadersFrame.headers().add(entry.getKey(), entry.getValue()); } Channels.write(ctx, future, spdyHeadersFrame, remoteAddress); } } else { SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId); spdyDataFrame.setLast(true); Channels.write(ctx, future, spdyDataFrame, remoteAddress); } } else { SpdyDataFrame[] spdyDataFrames = createSpdyDataFrames(streamId, chunk.getContent()); ChannelFuture dataFuture = getDataFuture(ctx, future, spdyDataFrames, remoteAddress); // Trigger a write dataFuture.setSuccess(); } } private ChannelFuture getMessageFuture( ChannelHandlerContext ctx, MessageEvent e, int streamId, HttpMessage httpMessage) { if (!httpMessage.getContent().readable()) { return e.getFuture(); } // Create SPDY Data Frames out of message content SpdyDataFrame[] spdyDataFrames = createSpdyDataFrames(streamId, httpMessage.getContent()); if (spdyDataFrames.length > 0) { spdyDataFrames[spdyDataFrames.length - 1].setLast(true); } return getDataFuture(ctx, e.getFuture(), spdyDataFrames, e.getRemoteAddress()); } private static ChannelFuture getDataFuture( ChannelHandlerContext ctx, ChannelFuture future, SpdyDataFrame[] spdyDataFrames, SocketAddress remoteAddress) { ChannelFuture dataFuture = future; for (int i = spdyDataFrames.length; --i >= 0;) { future = Channels.future(ctx.getChannel()); future.addListener(new SpdyFrameWriter(ctx, new DownstreamMessageEvent( ctx.getChannel(), dataFuture, spdyDataFrames[i], remoteAddress))); dataFuture = future; } return dataFuture; } private static class SpdyFrameWriter implements ChannelFutureListener { private final ChannelHandlerContext ctx; private final MessageEvent e; SpdyFrameWriter(ChannelHandlerContext ctx, MessageEvent e) { this.ctx = ctx; this.e = e; } public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { ctx.sendDownstream(e); } else if (future.isCancelled()) { e.getFuture().cancel(); } else { e.getFuture().setFailure(future.getCause()); } } } private SpdySynStreamFrame createSynStreamFrame(HttpMessage httpMessage) throws Exception { boolean chunked = httpMessage.isChunked(); // Get the Stream-ID, Associated-To-Stream-ID, Priority, URL, and scheme from the headers int streamId = SpdyHttpHeaders.getStreamId(httpMessage); int associatedToStreamId = SpdyHttpHeaders.getAssociatedToStreamId(httpMessage); byte priority = SpdyHttpHeaders.getPriority(httpMessage); String URL = SpdyHttpHeaders.getUrl(httpMessage); String scheme = SpdyHttpHeaders.getScheme(httpMessage); SpdyHttpHeaders.removeStreamId(httpMessage); SpdyHttpHeaders.removeAssociatedToStreamId(httpMessage); SpdyHttpHeaders.removePriority(httpMessage); SpdyHttpHeaders.removeUrl(httpMessage); SpdyHttpHeaders.removeScheme(httpMessage); // The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding // headers are not valid and MUST not be sent. httpMessage.headers().remove(HttpHeaders.Names.CONNECTION); httpMessage.headers().remove("Keep-Alive"); httpMessage.headers().remove("Proxy-Connection"); httpMessage.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(streamId, associatedToStreamId, priority); spdySynStreamFrame.setLast(!chunked && !httpMessage.getContent().readable()); // Unfold the first line of the message into name/value pairs if (httpMessage instanceof HttpRequest) { HttpRequest httpRequest = (HttpRequest) httpMessage; SpdyHeaders.setMethod(spdyVersion, spdySynStreamFrame, httpRequest.getMethod()); SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, httpRequest.getUri()); SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.getProtocolVersion()); } if (httpMessage instanceof HttpResponse) { HttpResponse httpResponse = (HttpResponse) httpMessage; SpdyHeaders.setStatus(spdyVersion, spdySynStreamFrame, httpResponse.getStatus()); SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, URL); SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.getProtocolVersion()); spdySynStreamFrame.setUnidirectional(true); } // Replace the HTTP host header with the SPDY host header String host = HttpHeaders.getHost(httpMessage); httpMessage.headers().remove(HttpHeaders.Names.HOST); SpdyHeaders.setHost(spdySynStreamFrame, host); // Set the SPDY scheme header if (scheme == null) { scheme = "https"; } SpdyHeaders.setScheme(spdyVersion, spdySynStreamFrame, scheme); // Transfer the remaining HTTP headers for (Map.Entry entry: httpMessage.headers()) { spdySynStreamFrame.headers().add(entry.getKey(), entry.getValue()); } return spdySynStreamFrame; } private SpdySynReplyFrame createSynReplyFrame(HttpResponse httpResponse) throws Exception { boolean chunked = httpResponse.isChunked(); // Get the Stream-ID from the headers int streamId = SpdyHttpHeaders.getStreamId(httpResponse); SpdyHttpHeaders.removeStreamId(httpResponse); // The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding // headers are not valid and MUST not be sent. httpResponse.headers().remove(HttpHeaders.Names.CONNECTION); httpResponse.headers().remove("Keep-Alive"); httpResponse.headers().remove("Proxy-Connection"); httpResponse.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId); spdySynReplyFrame.setLast(!chunked && !httpResponse.getContent().readable()); // Unfold the first line of the response into name/value pairs SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, httpResponse.getStatus()); SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, httpResponse.getProtocolVersion()); // Transfer the remaining HTTP headers for (Map.Entry entry: httpResponse.headers()) { spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue()); } return spdySynReplyFrame; } private SpdyDataFrame[] createSpdyDataFrames(int streamId, ChannelBuffer content) { int readableBytes = content.readableBytes(); int count = readableBytes / SPDY_MAX_LENGTH; if (readableBytes % SPDY_MAX_LENGTH > 0) { count++; } SpdyDataFrame[] spdyDataFrames = new SpdyDataFrame[count]; for (int i = 0; i < count; i ++) { SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId); int dataSize = Math.min(content.readableBytes(), SPDY_MAX_LENGTH); spdyDataFrame.setData(content.readSlice(dataSize)); spdyDataFrames[i] = spdyDataFrame; } return spdyDataFrames; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyHttpHeaders.java000066400000000000000000000122041225554127700321650ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMessage; /** * Provides the constants for the header names and the utility methods * used by the {@link SpdyHttpDecoder} and {@link SpdyHttpEncoder}. * @apiviz.stereotype static */ public final class SpdyHttpHeaders { /** * SPDY HTTP header names * @apiviz.stereotype static */ public static final class Names { /** * {@code "X-SPDY-Stream-ID"} */ public static final String STREAM_ID = "X-SPDY-Stream-ID"; /** * {@code "X-SPDY-Associated-To-Stream-ID"} */ public static final String ASSOCIATED_TO_STREAM_ID = "X-SPDY-Associated-To-Stream-ID"; /** * {@code "X-SPDY-Priority"} */ public static final String PRIORITY = "X-SPDY-Priority"; /** * {@code "X-SPDY-URL"} */ public static final String URL = "X-SPDY-URL"; /** * {@code "X-SPDY-Scheme"} */ public static final String SCHEME = "X-SPDY-Scheme"; private Names() { } } private SpdyHttpHeaders() { } /** * Removes the {@code "X-SPDY-Stream-ID"} header. */ public static void removeStreamId(HttpMessage message) { message.headers().remove(Names.STREAM_ID); } /** * Returns the value of the {@code "X-SPDY-Stream-ID"} header. */ public static int getStreamId(HttpMessage message) { return HttpHeaders.getIntHeader(message, Names.STREAM_ID); } /** * Sets the {@code "X-SPDY-Stream-ID"} header. */ public static void setStreamId(HttpMessage message, int streamId) { HttpHeaders.setIntHeader(message, Names.STREAM_ID, streamId); } /** * Removes the {@code "X-SPDY-Associated-To-Stream-ID"} header. */ public static void removeAssociatedToStreamId(HttpMessage message) { message.headers().remove(Names.ASSOCIATED_TO_STREAM_ID); } /** * Returns the value of the {@code "X-SPDY-Associated-To-Stream-ID"} header. * * @return the header value or {@code 0} if there is no such header or * if the header value is not a number */ public static int getAssociatedToStreamId(HttpMessage message) { return HttpHeaders.getIntHeader(message, Names.ASSOCIATED_TO_STREAM_ID, 0); } /** * Sets the {@code "X-SPDY-Associated-To-Stream-ID"} header. */ public static void setAssociatedToStreamId(HttpMessage message, int associatedToStreamId) { HttpHeaders.setIntHeader(message, Names.ASSOCIATED_TO_STREAM_ID, associatedToStreamId); } /** * Removes the {@code "X-SPDY-Priority"} header. */ public static void removePriority(HttpMessage message) { message.headers().remove(Names.PRIORITY); } /** * Returns the value of the {@code "X-SPDY-Priority"} header. * * @return the header value or {@code 0} if there is no such header or * if the header value is not a number */ public static byte getPriority(HttpMessage message) { return (byte) HttpHeaders.getIntHeader(message, Names.PRIORITY, 0); } /** * Sets the {@code "X-SPDY-Priority"} header. */ public static void setPriority(HttpMessage message, byte priority) { HttpHeaders.setIntHeader(message, Names.PRIORITY, priority); } /** * Removes the {@code "X-SPDY-URL"} header. */ public static void removeUrl(HttpMessage message) { message.headers().remove(Names.URL); } /** * Returns the value of the {@code "X-SPDY-URL"} header. */ public static String getUrl(HttpMessage message) { return message.headers().get(Names.URL); } /** * Sets the {@code "X-SPDY-URL"} header. */ public static void setUrl(HttpMessage message, String url) { message.headers().set(Names.URL, url); } /** * Removes the {@code "X-SPDY-Scheme"} header. */ public static void removeScheme(HttpMessage message) { message.headers().remove(Names.SCHEME); } /** * Returns the value of the {@code "X-SPDY-Scheme"} header. */ public static String getScheme(HttpMessage message) { return message.headers().get(Names.SCHEME); } /** * Sets the {@code "X-SPDY-Scheme"} header. */ public static void setScheme(HttpMessage message, String scheme) { message.headers().set(Names.SCHEME, scheme); } } SpdyHttpResponseStreamIdHandler.java000066400000000000000000000051301225554127700352600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpResponse; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * {@link SimpleChannelHandler} that takes care of adding the right streamId to the * {@link HttpResponse} if one is not present. This makes it possible to just re-use plan handlers current used * for HTTP. */ public class SpdyHttpResponseStreamIdHandler extends SimpleChannelHandler { private static final Integer NO_ID = -1; private final Queue ids = new ConcurrentLinkedQueue(); @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof HttpMessage) { boolean contains = ((HttpMessage) e.getMessage()).headers().contains(SpdyHttpHeaders.Names.STREAM_ID); if (!contains) { ids.add(NO_ID); } else { ids.add(SpdyHttpHeaders.getStreamId((HttpMessage) e.getMessage())); } } else if (e.getMessage() instanceof SpdyRstStreamFrame) { // remove id from the queue ids.remove(((SpdyRstStreamFrame) e.getMessage()).getStreamId()); } super.messageReceived(ctx, e); } @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof HttpResponse) { HttpResponse response = (HttpResponse) e.getMessage(); Integer id = ids.poll(); if (id != null && id.intValue() != NO_ID && !response.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) { SpdyHttpHeaders.setStreamId(response, id); } } super.writeRequested(ctx, e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyOrHttpChooser.java000066400000000000000000000133471225554127700325260ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import javax.net.ssl.SSLEngine; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.ssl.SslHandler; /** * {@link ChannelUpstreamHandler} which is responsible to setup the {@link ChannelPipeline} either for * HTTP or SPDY. This offers an easy way for users to support both at the same time while not care to * much about the low-level details. * */ public abstract class SpdyOrHttpChooser implements ChannelUpstreamHandler { public enum SelectedProtocol { SpdyVersion3_1, SpdyVersion3, HttpVersion1_1, HttpVersion1_0, None } private final int maxSpdyContentLength; private final int maxHttpContentLength; protected SpdyOrHttpChooser(int maxSpdyContentLength, int maxHttpContentLength) { this.maxSpdyContentLength = maxSpdyContentLength; this.maxHttpContentLength = maxHttpContentLength; } /** * Return the {@link SelectedProtocol} for the {@link SSLEngine}. If its not known yet implementations * MUST return {@link SelectedProtocol#None}. * */ protected abstract SelectedProtocol getProtocol(SSLEngine engine); public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { // Get the SslHandler from the ChannelPipeline so we can obtain the SslEngine from it. SslHandler handler = ctx.getPipeline().get(SslHandler.class); if (handler == null) { // SslHandler is needed by SPDY by design. throw new IllegalStateException("SslHandler is needed for SPDY"); } ChannelPipeline pipeline = ctx.getPipeline(); SelectedProtocol protocol = getProtocol(handler.getEngine()); switch (protocol) { case None: // Not done with choosing the protocol, so just return here for now, return; case SpdyVersion3: addSpdyHandlers(ctx, SpdyVersion.SPDY_3); break; case SpdyVersion3_1: addSpdyHandlers(ctx, SpdyVersion.SPDY_3_1); break; case HttpVersion1_0: case HttpVersion1_1: addHttpHandlers(ctx); break; default: throw new IllegalStateException("Unknown SelectedProtocol"); } // When we reached here we can remove this handler as its now clear what protocol we want to use // from this point on. pipeline.remove(this); ctx.sendUpstream(e); } /** * Add all {@link ChannelHandler}'s that are needed for SPDY with the given version. */ protected void addSpdyHandlers(ChannelHandlerContext ctx, SpdyVersion version) { ChannelPipeline pipeline = ctx.getPipeline(); pipeline.addLast("spdyDecoder", new SpdyFrameDecoder(version)); pipeline.addLast("spdyEncoder", new SpdyFrameEncoder(version)); pipeline.addLast("spdySessionHandler", new SpdySessionHandler(version, true)); pipeline.addLast("spdyHttpEncoder", new SpdyHttpEncoder(version)); pipeline.addLast("spdyHttpDecoder", new SpdyHttpDecoder(version, maxSpdyContentLength)); pipeline.addLast("spdyStreamIdHandler", new SpdyHttpResponseStreamIdHandler()); pipeline.addLast("httpRquestHandler", createHttpRequestHandlerForSpdy()); } /** * Add all {@link ChannelHandler}'s that are needed for HTTP. */ protected void addHttpHandlers(ChannelHandlerContext ctx) { ChannelPipeline pipeline = ctx.getPipeline(); pipeline.addLast("httpRquestDecoder", new HttpRequestDecoder()); pipeline.addLast("httpResponseEncoder", new HttpResponseEncoder()); pipeline.addLast("httpChunkAggregator", new HttpChunkAggregator(maxHttpContentLength)); pipeline.addLast("httpRquestHandler", createHttpRequestHandlerForHttp()); } /** * Create the {@link ChannelUpstreamHandler} that is responsible for handling the {@link HttpRequest}'s * when the {@link SelectedProtocol} was {@link SelectedProtocol#HttpVersion1_0} or * {@link SelectedProtocol#HttpVersion1_1} */ protected abstract ChannelUpstreamHandler createHttpRequestHandlerForHttp(); /** * Create the {@link ChannelUpstreamHandler} that is responsible for handling the {@link HttpRequest}'s * when the {@link SelectedProtocol} was {@link SelectedProtocol#SpdyVersion3} or * {@link SelectedProtocol#SpdyVersion3_1}. * * Bye default this method will just delecate to {@link #createHttpRequestHandlerForHttp()}, but * sub-classes may override this to change the behaviour. */ protected ChannelUpstreamHandler createHttpRequestHandlerForSpdy() { return createHttpRequestHandlerForHttp(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyPingFrame.java000066400000000000000000000016251225554127700316270ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol PING Frame */ public interface SpdyPingFrame extends SpdyFrame { /** * Returns the ID of this frame. */ int getId(); /** * Sets the ID of this frame. */ void setId(int id); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyProtocolException.java000066400000000000000000000026571225554127700334450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * An {@link Exception} which is thrown when the received frame cannot * be decoded by the {@link SpdyFrameDecoder}. * @apiviz.exclude */ public class SpdyProtocolException extends Exception { private static final long serialVersionUID = 7870000537743847264L; /** * Creates a new instance. */ public SpdyProtocolException() { } /** * Creates a new instance. */ public SpdyProtocolException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public SpdyProtocolException(String message) { super(message); } /** * Creates a new instance. */ public SpdyProtocolException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyRstStreamFrame.java000066400000000000000000000017241225554127700326560ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol RST_STREAM Frame */ public interface SpdyRstStreamFrame extends SpdyStreamFrame { /** * Returns the status of this frame. */ SpdyStreamStatus getStatus(); /** * Sets the status of this frame. */ void setStatus(SpdyStreamStatus status); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdySession.java000066400000000000000000000253031225554127700314010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.channel.MessageEvent; import java.util.Comparator; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; final class SpdySession { private static final SpdyProtocolException STREAM_CLOSED = new SpdyProtocolException("Stream closed"); private final AtomicInteger activeLocalStreams = new AtomicInteger(); private final AtomicInteger activeRemoteStreams = new AtomicInteger(); private final Map activeStreams = new ConcurrentHashMap(); private final AtomicInteger sendWindowSize; private final AtomicInteger receiveWindowSize; public SpdySession(int sendWindowSize, int receiveWindowSize) { this.sendWindowSize = new AtomicInteger(sendWindowSize); this.receiveWindowSize = new AtomicInteger(receiveWindowSize); } int numActiveStreams(boolean remote) { if (remote) { return activeRemoteStreams.get(); } else { return activeLocalStreams.get(); } } boolean noActiveStreams() { return activeStreams.isEmpty(); } boolean isActiveStream(int streamId) { return activeStreams.containsKey(streamId); } // Stream-IDs should be iterated in priority order Set getActiveStreams() { TreeSet StreamIds = new TreeSet(new PriorityComparator()); StreamIds.addAll(activeStreams.keySet()); return StreamIds; } void acceptStream( int streamId, byte priority, boolean remoteSideClosed, boolean localSideClosed, int sendWindowSize, int receiveWindowSize, boolean remote) { if (!remoteSideClosed || !localSideClosed) { StreamState state = activeStreams.put( streamId, new StreamState(priority, remoteSideClosed, localSideClosed, sendWindowSize, receiveWindowSize)); if (state == null) { if (remote) { activeRemoteStreams.incrementAndGet(); } else { activeLocalStreams.incrementAndGet(); } } } } private StreamState removeActiveStream(int streamId, boolean remote) { StreamState state = activeStreams.remove(streamId); if (state != null) { if (remote) { activeRemoteStreams.decrementAndGet(); } else { activeLocalStreams.decrementAndGet(); } } return state; } void removeStream(int streamId, boolean remote) { StreamState state = removeActiveStream(streamId, remote); if (state != null) { MessageEvent e = state.removePendingWrite(); while (e != null) { e.getFuture().setFailure(STREAM_CLOSED); e = state.removePendingWrite(); } } } boolean isRemoteSideClosed(int streamId) { StreamState state = activeStreams.get(streamId); return state == null || state.isRemoteSideClosed(); } void closeRemoteSide(int streamId, boolean remote) { StreamState state = activeStreams.get(streamId); if (state != null) { state.closeRemoteSide(); if (state.isLocalSideClosed()) { removeActiveStream(streamId, remote); } } } boolean isLocalSideClosed(int streamId) { StreamState state = activeStreams.get(streamId); return state == null || state.isLocalSideClosed(); } void closeLocalSide(int streamId, boolean remote) { StreamState state = activeStreams.get(streamId); if (state != null) { state.closeLocalSide(); if (state.isRemoteSideClosed()) { removeActiveStream(streamId, remote); } } } /* * hasReceivedReply and receivedReply are only called from messageReceived * no need to synchronize access to the StreamState */ boolean hasReceivedReply(int streamId) { StreamState state = activeStreams.get(streamId); return state != null && state.hasReceivedReply(); } void receivedReply(int streamId) { StreamState state = activeStreams.get(streamId); if (state != null) { state.receivedReply(); } } int getSendWindowSize(int streamId) { if (streamId == SPDY_SESSION_STREAM_ID) { return sendWindowSize.get(); } StreamState state = activeStreams.get(streamId); return state != null ? state.getSendWindowSize() : -1; } int updateSendWindowSize(int streamId, int deltaWindowSize) { if (streamId == SPDY_SESSION_STREAM_ID) { return sendWindowSize.addAndGet(deltaWindowSize); } StreamState state = activeStreams.get(streamId); return state != null ? state.updateSendWindowSize(deltaWindowSize) : -1; } int updateReceiveWindowSize(int streamId, int deltaWindowSize) { if (streamId == SPDY_SESSION_STREAM_ID) { return receiveWindowSize.addAndGet(deltaWindowSize); } StreamState state = activeStreams.get(streamId); if (deltaWindowSize > 0) { state.setReceiveWindowSizeLowerBound(0); } return state != null ? state.updateReceiveWindowSize(deltaWindowSize) : -1; } int getReceiveWindowSizeLowerBound(int streamId) { if (streamId == SPDY_SESSION_STREAM_ID) { return 0; } StreamState state = activeStreams.get(streamId); return state != null ? state.getReceiveWindowSizeLowerBound() : 0; } void updateAllSendWindowSizes(int deltaWindowSize) { for (StreamState state: activeStreams.values()) { state.updateSendWindowSize(deltaWindowSize); } } void updateAllReceiveWindowSizes(int deltaWindowSize) { for (StreamState state: activeStreams.values()) { state.updateReceiveWindowSize(deltaWindowSize); if (deltaWindowSize < 0) { state.setReceiveWindowSizeLowerBound(deltaWindowSize); } } } boolean putPendingWrite(int streamId, MessageEvent evt) { StreamState state = activeStreams.get(streamId); return state != null && state.putPendingWrite(evt); } MessageEvent getPendingWrite(int streamId) { if (streamId == SPDY_SESSION_STREAM_ID) { for (Integer id : getActiveStreams()) { StreamState state = activeStreams.get(id); if (state.getSendWindowSize() > 0) { MessageEvent e = state.getPendingWrite(); if (e != null) { return e; } } } return null; } StreamState state = activeStreams.get(streamId); return state != null ? state.getPendingWrite() : null; } MessageEvent removePendingWrite(int streamId) { StreamState state = activeStreams.get(streamId); return state != null ? state.removePendingWrite() : null; } private static final class StreamState { private final byte priority; private volatile boolean remoteSideClosed; private volatile boolean localSideClosed; private boolean receivedReply; private final AtomicInteger sendWindowSize; private final AtomicInteger receiveWindowSize; private volatile int receiveWindowSizeLowerBound; private final ConcurrentLinkedQueue pendingWriteQueue = new ConcurrentLinkedQueue(); StreamState( byte priority, boolean remoteSideClosed, boolean localSideClosed, int sendWindowSize, int receiveWindowSize) { this.priority = priority; this.remoteSideClosed = remoteSideClosed; this.localSideClosed = localSideClosed; this.sendWindowSize = new AtomicInteger(sendWindowSize); this.receiveWindowSize = new AtomicInteger(receiveWindowSize); } byte getPriority() { return priority; } boolean isRemoteSideClosed() { return remoteSideClosed; } void closeRemoteSide() { remoteSideClosed = true; } boolean isLocalSideClosed() { return localSideClosed; } void closeLocalSide() { localSideClosed = true; } boolean hasReceivedReply() { return receivedReply; } void receivedReply() { receivedReply = true; } int getSendWindowSize() { return sendWindowSize.get(); } int updateSendWindowSize(int deltaWindowSize) { return sendWindowSize.addAndGet(deltaWindowSize); } int updateReceiveWindowSize(int deltaWindowSize) { return receiveWindowSize.addAndGet(deltaWindowSize); } int getReceiveWindowSizeLowerBound() { return receiveWindowSizeLowerBound; } void setReceiveWindowSizeLowerBound(int receiveWindowSizeLowerBound) { this.receiveWindowSizeLowerBound = receiveWindowSizeLowerBound; } boolean putPendingWrite(MessageEvent evt) { return pendingWriteQueue.offer(evt); } MessageEvent getPendingWrite() { return pendingWriteQueue.peek(); } MessageEvent removePendingWrite() { return pendingWriteQueue.poll(); } } private final class PriorityComparator implements Comparator { PriorityComparator() { } public int compare(Integer id1, Integer id2) { StreamState state1 = activeStreams.get(id1); StreamState state2 = activeStreams.get(id2); return state1.getPriority() - state2.getPriority(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdySessionHandler.java000066400000000000000000001176401225554127700327050ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; import java.util.concurrent.atomic.AtomicInteger; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; /** * Manages streams within a SPDY session. */ public class SpdySessionHandler extends SimpleChannelUpstreamHandler implements ChannelDownstreamHandler { private static final SpdyProtocolException PROTOCOL_EXCEPTION = new SpdyProtocolException(); private static final int DEFAULT_WINDOW_SIZE = 64 * 1024; // 64 KB default initial window size private volatile int initialSendWindowSize = DEFAULT_WINDOW_SIZE; private volatile int initialReceiveWindowSize = DEFAULT_WINDOW_SIZE; private final SpdySession spdySession = new SpdySession(initialSendWindowSize, initialReceiveWindowSize); private volatile int lastGoodStreamId; private static final int DEFAULT_MAX_CONCURRENT_STREAMS = Integer.MAX_VALUE; private volatile int remoteConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS; private volatile int localConcurrentStreams = DEFAULT_MAX_CONCURRENT_STREAMS; private final Object flowControlLock = new Object(); private final AtomicInteger pings = new AtomicInteger(); private volatile boolean sentGoAwayFrame; private volatile boolean receivedGoAwayFrame; private volatile ChannelFutureListener closeSessionFutureListener; private final boolean server; private final int minorVersion; private final boolean sessionFlowControl; /** * Creates a new session handler. * * @param spdyVersion the protocol version * @param server {@code true} if and only if this session handler should * handle the server endpoint of the connection. * {@code false} if and only if this session handler should * handle the client endpoint of the connection. */ public SpdySessionHandler(SpdyVersion spdyVersion, boolean server) { if (spdyVersion == null) { throw new NullPointerException("spdyVersion"); } this.server = server; minorVersion = spdyVersion.getMinorVersion(); sessionFlowControl = spdyVersion.useSessionFlowControl(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof SpdyDataFrame) { /* * SPDY Data frame processing requirements: * * If an endpoint receives a data frame for a Stream-ID which is not open * and the endpoint has not sent a GOAWAY frame, it must issue a stream error * with the error code INVALID_STREAM for the Stream-ID. * * If an endpoint which created the stream receives a data frame before receiving * a SYN_REPLY on that stream, it is a protocol error, and the recipient must * issue a stream error with the status code PROTOCOL_ERROR for the Stream-ID. * * If an endpoint receives multiple data frames for invalid Stream-IDs, * it may close the session. * * If an endpoint refuses a stream it must ignore any data frames for that stream. * * If an endpoint receives a data frame after the stream is half-closed from the * sender, it must send a RST_STREAM frame with the status STREAM_ALREADY_CLOSED. * * If an endpoint receives a data frame after the stream is closed, it must send * a RST_STREAM frame with the status PROTOCOL_ERROR. */ SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; int streamId = spdyDataFrame.getStreamId(); if (sessionFlowControl) { int deltaWindowSize = -1 * spdyDataFrame.getData().readableBytes(); int newSessionWindowSize = spdySession.updateReceiveWindowSize(SPDY_SESSION_STREAM_ID, deltaWindowSize); // Check if session window size is reduced beyond allowable lower bound if (newSessionWindowSize < 0) { issueSessionError(ctx, e.getChannel(), e.getRemoteAddress(), SpdySessionStatus.PROTOCOL_ERROR); return; } // Send a WINDOW_UPDATE frame if less than half the session window size remains if (newSessionWindowSize <= initialReceiveWindowSize / 2) { deltaWindowSize = initialReceiveWindowSize - newSessionWindowSize; spdySession.updateReceiveWindowSize(SPDY_SESSION_STREAM_ID, deltaWindowSize); SpdyWindowUpdateFrame spdyWindowUpdateFrame = new DefaultSpdyWindowUpdateFrame(SPDY_SESSION_STREAM_ID, deltaWindowSize); Channels.write( ctx, Channels.future(e.getChannel()), spdyWindowUpdateFrame, e.getRemoteAddress()); } } // Check if we received a data frame for a Stream-ID which is not open if (!spdySession.isActiveStream(streamId)) { if (streamId <= lastGoodStreamId) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR); } else if (!sentGoAwayFrame) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.INVALID_STREAM); } return; } // Check if we received a data frame for a stream which is half-closed if (spdySession.isRemoteSideClosed(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.STREAM_ALREADY_CLOSED); return; } // Check if we received a data frame before receiving a SYN_REPLY if (!isRemoteInitiatedId(streamId) && !spdySession.hasReceivedReply(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR); return; } /* * SPDY Data frame flow control processing requirements: * * Recipient should not send a WINDOW_UPDATE frame as it consumes the last data frame. */ // Update receive window size int deltaWindowSize = -1 * spdyDataFrame.getData().readableBytes(); int newWindowSize = spdySession.updateReceiveWindowSize(streamId, deltaWindowSize); // Window size can become negative if we sent a SETTINGS frame that reduces the // size of the transfer window after the peer has written data frames. // The value is bounded by the length that SETTINGS frame decrease the window. // This difference is stored for the session when writing the SETTINGS frame // and is cleared once we send a WINDOW_UPDATE frame. if (newWindowSize < spdySession.getReceiveWindowSizeLowerBound(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.FLOW_CONTROL_ERROR); return; } // Window size became negative due to sender writing frame before receiving SETTINGS // Send data frames upstream in initialReceiveWindowSize chunks if (newWindowSize < 0) { while (spdyDataFrame.getData().readableBytes() > initialReceiveWindowSize) { SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(streamId); partialDataFrame.setData(spdyDataFrame.getData().readSlice(initialReceiveWindowSize)); Channels.fireMessageReceived(ctx, partialDataFrame, e.getRemoteAddress()); } } // Send a WINDOW_UPDATE frame if less than half the stream window size remains if (newWindowSize <= initialReceiveWindowSize / 2 && !spdyDataFrame.isLast()) { deltaWindowSize = initialReceiveWindowSize - newWindowSize; spdySession.updateReceiveWindowSize(streamId, deltaWindowSize); SpdyWindowUpdateFrame spdyWindowUpdateFrame = new DefaultSpdyWindowUpdateFrame(streamId, deltaWindowSize); Channels.write( ctx, Channels.future(e.getChannel()), spdyWindowUpdateFrame, e.getRemoteAddress()); } // Close the remote side of the stream if this is the last frame if (spdyDataFrame.isLast()) { halfCloseStream(streamId, true, e.getFuture()); } } else if (msg instanceof SpdySynStreamFrame) { /* * SPDY SYN_STREAM frame processing requirements: * * If an endpoint receives a SYN_STREAM with a Stream-ID that is less than * any previously received SYN_STREAM, it must issue a session error with * the status PROTOCOL_ERROR. * * If an endpoint receives multiple SYN_STREAM frames with the same active * Stream-ID, it must issue a stream error with the status code PROTOCOL_ERROR. * * The recipient can reject a stream by sending a stream error with the * status code REFUSED_STREAM. */ SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; int streamId = spdySynStreamFrame.getStreamId(); // Check if we received a valid SYN_STREAM frame if (spdySynStreamFrame.isInvalid() || !isRemoteInitiatedId(streamId) || spdySession.isActiveStream(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR); return; } // Stream-IDs must be monotonically increasing if (streamId <= lastGoodStreamId) { issueSessionError(ctx, e.getChannel(), e.getRemoteAddress(), SpdySessionStatus.PROTOCOL_ERROR); return; } // Try to accept the stream byte priority = spdySynStreamFrame.getPriority(); boolean remoteSideClosed = spdySynStreamFrame.isLast(); boolean localSideClosed = spdySynStreamFrame.isUnidirectional(); if (!acceptStream(streamId, priority, remoteSideClosed, localSideClosed)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.REFUSED_STREAM); return; } } else if (msg instanceof SpdySynReplyFrame) { /* * SPDY SYN_REPLY frame processing requirements: * * If an endpoint receives multiple SYN_REPLY frames for the same active Stream-ID * it must issue a stream error with the status code STREAM_IN_USE. */ SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; int streamId = spdySynReplyFrame.getStreamId(); // Check if we received a valid SYN_REPLY frame if (spdySynReplyFrame.isInvalid() || isRemoteInitiatedId(streamId) || spdySession.isRemoteSideClosed(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.INVALID_STREAM); return; } // Check if we have received multiple frames for the same Stream-ID if (spdySession.hasReceivedReply(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.STREAM_IN_USE); return; } spdySession.receivedReply(streamId); // Close the remote side of the stream if this is the last frame if (spdySynReplyFrame.isLast()) { halfCloseStream(streamId, true, e.getFuture()); } } else if (msg instanceof SpdyRstStreamFrame) { /* * SPDY RST_STREAM frame processing requirements: * * After receiving a RST_STREAM on a stream, the receiver must not send * additional frames on that stream. * * An endpoint must not send a RST_STREAM in response to a RST_STREAM. */ SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; removeStream(spdyRstStreamFrame.getStreamId(), e.getFuture()); } else if (msg instanceof SpdySettingsFrame) { SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; int settingsMinorVersion = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MINOR_VERSION); if (settingsMinorVersion >= 0 && settingsMinorVersion != minorVersion) { // Settings frame had the wrong minor version issueSessionError(ctx, e.getChannel(), e.getRemoteAddress(), SpdySessionStatus.PROTOCOL_ERROR); return; } int newConcurrentStreams = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS); if (newConcurrentStreams >= 0) { remoteConcurrentStreams = newConcurrentStreams; } // Persistence flag are inconsistent with the use of SETTINGS to communicate // the initial window size. Remove flags from the sender requesting that the // value be persisted. Remove values that the sender indicates are persisted. if (spdySettingsFrame.isPersisted(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE)) { spdySettingsFrame.removeValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); } spdySettingsFrame.setPersistValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE, false); int newInitialWindowSize = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); if (newInitialWindowSize >= 0) { updateInitialSendWindowSize(newInitialWindowSize); } } else if (msg instanceof SpdyPingFrame) { /* * SPDY PING frame processing requirements: * * Receivers of a PING frame should send an identical frame to the sender * as soon as possible. * * Receivers of a PING frame must ignore frames that it did not initiate */ SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; if (isRemoteInitiatedId(spdyPingFrame.getId())) { Channels.write(ctx, Channels.future(e.getChannel()), spdyPingFrame, e.getRemoteAddress()); return; } // Note: only checks that there are outstanding pings since uniqueness is not enforced if (pings.get() == 0) { return; } pings.getAndDecrement(); } else if (msg instanceof SpdyGoAwayFrame) { receivedGoAwayFrame = true; } else if (msg instanceof SpdyHeadersFrame) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; int streamId = spdyHeadersFrame.getStreamId(); // Check if we received a valid HEADERS frame if (spdyHeadersFrame.isInvalid()) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.PROTOCOL_ERROR); return; } if (spdySession.isRemoteSideClosed(streamId)) { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.INVALID_STREAM); return; } // Close the remote side of the stream if this is the last frame if (spdyHeadersFrame.isLast()) { halfCloseStream(streamId, true, e.getFuture()); } } else if (msg instanceof SpdyWindowUpdateFrame) { /* * SPDY WINDOW_UPDATE frame processing requirements: * * Receivers of a WINDOW_UPDATE that cause the window size to exceed 2^31 * must send a RST_STREAM with the status code FLOW_CONTROL_ERROR. * * Sender should ignore all WINDOW_UPDATE frames associated with a stream * after sending the last frame for the stream. */ SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg; int streamId = spdyWindowUpdateFrame.getStreamId(); int deltaWindowSize = spdyWindowUpdateFrame.getDeltaWindowSize(); // Ignore frames for half-closed streams if (streamId != SPDY_SESSION_STREAM_ID && spdySession.isLocalSideClosed(streamId)) { return; } // Check for numerical overflow if (spdySession.getSendWindowSize(streamId) > Integer.MAX_VALUE - deltaWindowSize) { if (streamId == SPDY_SESSION_STREAM_ID) { issueSessionError(ctx, e.getChannel(), e.getRemoteAddress(), SpdySessionStatus.PROTOCOL_ERROR); } else { issueStreamError(ctx, e.getRemoteAddress(), streamId, SpdyStreamStatus.FLOW_CONTROL_ERROR); } return; } updateSendWindowSize(ctx, streamId, deltaWindowSize); return; } super.messageReceived(ctx, e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Throwable cause = e.getCause(); if (cause instanceof SpdyProtocolException) { issueSessionError(ctx, e.getChannel(), null, SpdySessionStatus.PROTOCOL_ERROR); } super.exceptionCaught(ctx, e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) throws Exception { if (evt instanceof ChannelStateEvent) { ChannelStateEvent e = (ChannelStateEvent) evt; switch (e.getState()) { case OPEN: case CONNECTED: case BOUND: /* * SPDY connection requirements: * * When either endpoint closes the transport-level connection, * it must first send a GOAWAY frame. */ if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) { sendGoAwayFrame(ctx, e); return; } } } if (!(evt instanceof MessageEvent)) { ctx.sendDownstream(evt); return; } MessageEvent e = (MessageEvent) evt; Object msg = e.getMessage(); if (msg instanceof SpdyDataFrame) { SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; final int streamId = spdyDataFrame.getStreamId(); // Frames must not be sent on half-closed streams if (spdySession.isLocalSideClosed(streamId)) { e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } /* * SPDY Data frame flow control processing requirements: * * Sender must not send a data frame with data length greater * than the transfer window size. * * After sending each data frame, the sender decrements its * transfer window size by the amount of data transmitted. * * When the window size becomes less than or equal to 0, the * sender must pause transmitting data frames. */ synchronized (flowControlLock) { int dataLength = spdyDataFrame.getData().readableBytes(); int sendWindowSize = spdySession.getSendWindowSize(streamId); if (sessionFlowControl) { int sessionSendWindowSize = spdySession.getSendWindowSize(SPDY_SESSION_STREAM_ID); sendWindowSize = Math.min(sendWindowSize, sessionSendWindowSize); } if (sendWindowSize <= 0) { // Stream is stalled -- enqueue Data frame and return spdySession.putPendingWrite(streamId, e); return; } else if (sendWindowSize < dataLength) { // Stream is not stalled but we cannot send the entire frame spdySession.updateSendWindowSize(streamId, -1 * sendWindowSize); if (sessionFlowControl) { spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * sendWindowSize); } // Create a partial data frame whose length is the current window size SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(streamId); partialDataFrame.setData(spdyDataFrame.getData().readSlice(sendWindowSize)); // Enqueue the remaining data (will be the first frame queued) spdySession.putPendingWrite(streamId, e); ChannelFuture writeFuture = Channels.future(e.getChannel()); // The transfer window size is pre-decremented when sending a data frame downstream. // Close the session on write failures that leaves the transfer window in a corrupt state. final SocketAddress remoteAddress = e.getRemoteAddress(); final ChannelHandlerContext context = ctx; e.getFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Channel channel = future.getChannel(); issueSessionError( context, channel, remoteAddress, SpdySessionStatus.INTERNAL_ERROR); } } }); Channels.write(ctx, writeFuture, partialDataFrame, remoteAddress); return; } else { // Window size is large enough to send entire data frame spdySession.updateSendWindowSize(streamId, -1 * dataLength); if (sessionFlowControl) { spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * dataLength); } // The transfer window size is pre-decremented when sending a data frame downstream. // Close the session on write failures that leaves the transfer window in a corrupt state. final SocketAddress remoteAddress = e.getRemoteAddress(); final ChannelHandlerContext context = ctx; e.getFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Channel channel = future.getChannel(); issueSessionError( context, channel, remoteAddress, SpdySessionStatus.INTERNAL_ERROR); } } }); } } // Close the local side of the stream if this is the last frame if (spdyDataFrame.isLast()) { halfCloseStream(streamId, false, e.getFuture()); } } else if (msg instanceof SpdySynStreamFrame) { SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; int streamId = spdySynStreamFrame.getStreamId(); if (isRemoteInitiatedId(streamId)) { e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } byte priority = spdySynStreamFrame.getPriority(); boolean remoteSideClosed = spdySynStreamFrame.isUnidirectional(); boolean localSideClosed = spdySynStreamFrame.isLast(); if (!acceptStream(streamId, priority, remoteSideClosed, localSideClosed)) { e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } } else if (msg instanceof SpdySynReplyFrame) { SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; int streamId = spdySynReplyFrame.getStreamId(); // Frames must not be sent on half-closed streams if (!isRemoteInitiatedId(streamId) || spdySession.isLocalSideClosed(streamId)) { e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } // Close the local side of the stream if this is the last frame if (spdySynReplyFrame.isLast()) { halfCloseStream(streamId, false, e.getFuture()); } } else if (msg instanceof SpdyRstStreamFrame) { SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; removeStream(spdyRstStreamFrame.getStreamId(), e.getFuture()); } else if (msg instanceof SpdySettingsFrame) { SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; int settingsMinorVersion = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MINOR_VERSION); if (settingsMinorVersion >= 0 && settingsMinorVersion != minorVersion) { // Settings frame had the wrong minor version e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } int newConcurrentStreams = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS); if (newConcurrentStreams >= 0) { localConcurrentStreams = newConcurrentStreams; } // Persistence flag are inconsistent with the use of SETTINGS to communicate // the initial window size. Remove flags from the sender requesting that the // value be persisted. Remove values that the sender indicates are persisted. if (spdySettingsFrame.isPersisted(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE)) { spdySettingsFrame.removeValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); } spdySettingsFrame.setPersistValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE, false); int newInitialWindowSize = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); if (newInitialWindowSize >= 0) { updateInitialReceiveWindowSize(newInitialWindowSize); } } else if (msg instanceof SpdyPingFrame) { SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; if (isRemoteInitiatedId(spdyPingFrame.getId())) { e.getFuture().setFailure(new IllegalArgumentException( "invalid PING ID: " + spdyPingFrame.getId())); return; } pings.getAndIncrement(); } else if (msg instanceof SpdyGoAwayFrame) { // Why is this being sent? Intercept it and fail the write. // Should have sent a CLOSE ChannelStateEvent e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } else if (msg instanceof SpdyHeadersFrame) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; int streamId = spdyHeadersFrame.getStreamId(); // Frames must not be sent on half-closed streams if (spdySession.isLocalSideClosed(streamId)) { e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } // Close the local side of the stream if this is the last frame if (spdyHeadersFrame.isLast()) { halfCloseStream(streamId, false, e.getFuture()); } } else if (msg instanceof SpdyWindowUpdateFrame) { // Why is this being sent? Intercept it and fail the write. e.getFuture().setFailure(PROTOCOL_EXCEPTION); return; } ctx.sendDownstream(evt); } /* * SPDY Session Error Handling: * * When a session error occurs, the endpoint encountering the error must first * send a GOAWAY frame with the Stream-ID of the most recently received stream * from the remote endpoint, and the error code for why the session is terminating. * * After sending the GOAWAY frame, the endpoint must close the TCP connection. */ private void issueSessionError( ChannelHandlerContext ctx, Channel channel, SocketAddress remoteAddress, SpdySessionStatus status) { ChannelFuture future = sendGoAwayFrame(ctx, channel, remoteAddress, status); future.addListener(ChannelFutureListener.CLOSE); } /* * SPDY Stream Error Handling: * * Upon a stream error, the endpoint must send a RST_STREAM frame which contains * the Stream-ID for the stream where the error occurred and the error status which * caused the error. * * After sending the RST_STREAM, the stream is closed to the sending endpoint. * * Note: this is only called by the worker thread */ private void issueStreamError( ChannelHandlerContext ctx, SocketAddress remoteAddress, int streamId, SpdyStreamStatus status) { boolean fireMessageReceived = !spdySession.isRemoteSideClosed(streamId); ChannelFuture future = Channels.future(ctx.getChannel()); removeStream(streamId, future); SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, status); Channels.write(ctx, future, spdyRstStreamFrame, remoteAddress); if (fireMessageReceived) { Channels.fireMessageReceived(ctx, spdyRstStreamFrame, remoteAddress); } } /* * Helper functions */ private boolean isRemoteInitiatedId(int id) { boolean serverId = isServerId(id); return server && !serverId || !server && serverId; } // need to synchronize to prevent new streams from being created while updating active streams private synchronized void updateInitialSendWindowSize(int newInitialWindowSize) { int deltaWindowSize = newInitialWindowSize - initialSendWindowSize; initialSendWindowSize = newInitialWindowSize; spdySession.updateAllSendWindowSizes(deltaWindowSize); } // need to synchronize to prevent new streams from being created while updating active streams private synchronized void updateInitialReceiveWindowSize(int newInitialWindowSize) { int deltaWindowSize = newInitialWindowSize - initialReceiveWindowSize; initialReceiveWindowSize = newInitialWindowSize; spdySession.updateAllReceiveWindowSizes(deltaWindowSize); } // need to synchronize accesses to sentGoAwayFrame, lastGoodStreamId, and initial window sizes private synchronized boolean acceptStream( int streamId, byte priority, boolean remoteSideClosed, boolean localSideClosed) { // Cannot initiate any new streams after receiving or sending GOAWAY if (receivedGoAwayFrame || sentGoAwayFrame) { return false; } boolean remote = isRemoteInitiatedId(streamId); int maxConcurrentStreams = remote ? localConcurrentStreams : remoteConcurrentStreams; if (spdySession.numActiveStreams(remote) >= maxConcurrentStreams) { return false; } spdySession.acceptStream( streamId, priority, remoteSideClosed, localSideClosed, initialSendWindowSize, initialReceiveWindowSize, remote); if (remote) { lastGoodStreamId = streamId; } return true; } private void halfCloseStream(int streamId, boolean remote, ChannelFuture future) { if (remote) { spdySession.closeRemoteSide(streamId, isRemoteInitiatedId(streamId)); } else { spdySession.closeLocalSide(streamId, isRemoteInitiatedId(streamId)); } if (closeSessionFutureListener != null && spdySession.noActiveStreams()) { future.addListener(closeSessionFutureListener); } } private void removeStream(int streamId, ChannelFuture future) { spdySession.removeStream(streamId, isRemoteInitiatedId(streamId)); if (closeSessionFutureListener != null && spdySession.noActiveStreams()) { future.addListener(closeSessionFutureListener); } } private void updateSendWindowSize(ChannelHandlerContext ctx, int streamId, int deltaWindowSize) { synchronized (flowControlLock) { int newWindowSize = spdySession.updateSendWindowSize(streamId, deltaWindowSize); if (sessionFlowControl && streamId != SPDY_SESSION_STREAM_ID) { int sessionSendWindowSize = spdySession.getSendWindowSize(SPDY_SESSION_STREAM_ID); newWindowSize = Math.min(newWindowSize, sessionSendWindowSize); } while (newWindowSize > 0) { // Check if we have unblocked a stalled stream MessageEvent e = spdySession.getPendingWrite(streamId); if (e == null) { break; } SpdyDataFrame spdyDataFrame = (SpdyDataFrame) e.getMessage(); int dataFrameSize = spdyDataFrame.getData().readableBytes(); int writeStreamId = spdyDataFrame.getStreamId(); if (sessionFlowControl && streamId == SPDY_SESSION_STREAM_ID) { newWindowSize = Math.min(newWindowSize, spdySession.getSendWindowSize(writeStreamId)); } if (newWindowSize >= dataFrameSize) { // Window size is large enough to send entire data frame spdySession.removePendingWrite(writeStreamId); newWindowSize = spdySession.updateSendWindowSize(writeStreamId, -1 * dataFrameSize); if (sessionFlowControl) { int sessionSendWindowSize = spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * dataFrameSize); newWindowSize = Math.min(newWindowSize, sessionSendWindowSize); } // The transfer window size is pre-decremented when sending a data frame downstream. // Close the session on write failures that leaves the transfer window in a corrupt state. final SocketAddress remoteAddress = e.getRemoteAddress(); final ChannelHandlerContext context = ctx; e.getFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Channel channel = future.getChannel(); issueSessionError(context, channel, remoteAddress, SpdySessionStatus.INTERNAL_ERROR); } } }); // Close the local side of the stream if this is the last frame if (spdyDataFrame.isLast()) { halfCloseStream(writeStreamId, false, e.getFuture()); } Channels.write(ctx, e.getFuture(), spdyDataFrame, e.getRemoteAddress()); } else { // We can send a partial frame spdySession.updateSendWindowSize(writeStreamId, -1 * newWindowSize); if (sessionFlowControl) { spdySession.updateSendWindowSize(SPDY_SESSION_STREAM_ID, -1 * newWindowSize); } // Create a partial data frame whose length is the current window size SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(writeStreamId); partialDataFrame.setData(spdyDataFrame.getData().readSlice(newWindowSize)); ChannelFuture writeFuture = Channels.future(e.getChannel()); // The transfer window size is pre-decremented when sending a data frame downstream. // Close the session on write failures that leaves the transfer window in a corrupt state. final SocketAddress remoteAddress = e.getRemoteAddress(); final ChannelHandlerContext context = ctx; e.getFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Channel channel = future.getChannel(); issueSessionError(context, channel, remoteAddress, SpdySessionStatus.INTERNAL_ERROR); } } }); Channels.write(ctx, writeFuture, partialDataFrame, remoteAddress); newWindowSize = 0; } } } } private void sendGoAwayFrame(ChannelHandlerContext ctx, ChannelStateEvent e) { // Avoid NotYetConnectedException if (!e.getChannel().isConnected()) { ctx.sendDownstream(e); return; } ChannelFuture future = sendGoAwayFrame(ctx, e.getChannel(), null, SpdySessionStatus.OK); if (spdySession.noActiveStreams()) { future.addListener(new ClosingChannelFutureListener(ctx, e)); } else { closeSessionFutureListener = new ClosingChannelFutureListener(ctx, e); } } private synchronized ChannelFuture sendGoAwayFrame( ChannelHandlerContext ctx, Channel channel, SocketAddress remoteAddress, SpdySessionStatus status) { if (!sentGoAwayFrame) { sentGoAwayFrame = true; SpdyGoAwayFrame spdyGoAwayFrame = new DefaultSpdyGoAwayFrame(lastGoodStreamId, status); ChannelFuture future = Channels.future(channel); Channels.write(ctx, future, spdyGoAwayFrame, remoteAddress); return future; } return Channels.succeededFuture(channel); } private static final class ClosingChannelFutureListener implements ChannelFutureListener { private final ChannelHandlerContext ctx; private final ChannelStateEvent e; ClosingChannelFutureListener(ChannelHandlerContext ctx, ChannelStateEvent e) { this.ctx = ctx; this.e = e; } public void operationComplete(ChannelFuture sentGoAwayFuture) throws Exception { if (!(sentGoAwayFuture.getCause() instanceof ClosedChannelException)) { Channels.close(ctx, e.getFuture()); } else { e.getFuture().setSuccess(); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdySessionStatus.java000066400000000000000000000056071225554127700326120ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * The SPDY session status code and its description. * @apiviz.exclude */ public class SpdySessionStatus implements Comparable { /** * 0 OK */ public static final SpdySessionStatus OK = new SpdySessionStatus(0, "OK"); /** * 1 Protocol Error */ public static final SpdySessionStatus PROTOCOL_ERROR = new SpdySessionStatus(1, "PROTOCOL_ERROR"); /** * 2 Internal Error */ public static final SpdySessionStatus INTERNAL_ERROR = new SpdySessionStatus(2, "INTERNAL_ERROR"); /** * Returns the {@link SpdySessionStatus} represented by the specified code. * If the specified code is a defined SPDY status code, a cached instance * will be returned. Otherwise, a new instance will be returned. */ public static SpdySessionStatus valueOf(int code) { switch (code) { case 0: return OK; case 1: return PROTOCOL_ERROR; case 2: return INTERNAL_ERROR; } return new SpdySessionStatus(code, "UNKNOWN (" + code + ')'); } private final int code; private final String statusPhrase; /** * Creates a new instance with the specified {@code code} and its * {@code statusPhrase}. */ public SpdySessionStatus(int code, String statusPhrase) { if (statusPhrase == null) { throw new NullPointerException("statusPhrase"); } this.code = code; this.statusPhrase = statusPhrase; } /** * Returns the code of this status. */ public int getCode() { return code; } /** * Returns the status phrase of this status. */ public String getStatusPhrase() { return statusPhrase; } @Override public int hashCode() { return getCode(); } @Override public boolean equals(Object o) { if (!(o instanceof SpdySessionStatus)) { return false; } return getCode() == ((SpdySessionStatus) o).getCode(); } @Override public String toString() { return getStatusPhrase(); } public int compareTo(SpdySessionStatus o) { return getCode() - o.getCode(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdySettingsFrame.java000066400000000000000000000065441225554127700325370ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.Set; /** * A SPDY Protocol SETTINGS Frame */ public interface SpdySettingsFrame extends SpdyFrame { int SETTINGS_MINOR_VERSION = 0; int SETTINGS_UPLOAD_BANDWIDTH = 1; int SETTINGS_DOWNLOAD_BANDWIDTH = 2; int SETTINGS_ROUND_TRIP_TIME = 3; int SETTINGS_MAX_CONCURRENT_STREAMS = 4; int SETTINGS_CURRENT_CWND = 5; int SETTINGS_DOWNLOAD_RETRANS_RATE = 6; int SETTINGS_INITIAL_WINDOW_SIZE = 7; int SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8; /** * Returns a {@code Set} of the setting IDs. * The set's iterator will return the IDs in ascending order. */ Set getIds(); /** * Returns {@code true} if the setting ID has a value. */ boolean isSet(int id); /** * Returns the value of the setting ID. * Returns -1 if the setting ID is not set. */ int getValue(int id); /** * Sets the value of the setting ID. * The ID cannot be negative and cannot exceed 16777215. */ void setValue(int id, int value); /** * Sets the value of the setting ID. * Sets if the setting should be persisted (should only be set by the server). * Sets if the setting is persisted (should only be set by the client). * The ID cannot be negative and cannot exceed 16777215. */ void setValue(int id, int value, boolean persistVal, boolean persisted); /** * Removes the value of the setting ID. * Removes all persistence information for the setting. */ void removeValue(int id); /** * Returns {@code true} if this setting should be persisted. * Returns {@code false} if this setting should not be persisted * or if the setting ID has no value. */ boolean isPersistValue(int id); /** * Sets if this setting should be persisted. * Has no effect if the setting ID has no value. */ void setPersistValue(int id, boolean persistValue); /** * Returns {@code true} if this setting is persisted. * Returns {@code false} if this setting should not be persisted * or if the setting ID has no value. */ boolean isPersisted(int id); /** * Sets if this setting is persisted. * Has no effect if the setting ID has no value. */ void setPersisted(int id, boolean persisted); /** * Returns {@code true} if previously persisted settings should be cleared. */ boolean clearPreviouslyPersistedSettings(); /** * Sets if previously persisted settings should be cleared. */ void setClearPreviouslyPersistedSettings(boolean clear); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyStreamFrame.java000066400000000000000000000024161225554127700321640ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol Frame that is associated with an individual SPDY Stream */ public interface SpdyStreamFrame extends SpdyFrame { /** * Returns the Stream-ID of this frame. */ int getStreamId(); /** * Sets the Stream-ID of this frame. The Stream-ID must be positive. */ void setStreamId(int streamId); /** * Returns {@code true} if this frame is the last frame to be transmitted * on the stream. */ boolean isLast(); /** * Sets if this frame is the last frame to be transmitted on the stream. */ void setLast(boolean last); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyStreamStatus.java000066400000000000000000000115351225554127700324170ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * The SPDY stream status code and its description. * @apiviz.exclude */ public class SpdyStreamStatus implements Comparable { /** * 1 Protocol Error */ public static final SpdyStreamStatus PROTOCOL_ERROR = new SpdyStreamStatus(1, "PROTOCOL_ERROR"); /** * 2 Invalid Stream */ public static final SpdyStreamStatus INVALID_STREAM = new SpdyStreamStatus(2, "INVALID_STREAM"); /** * 3 Refused Stream */ public static final SpdyStreamStatus REFUSED_STREAM = new SpdyStreamStatus(3, "REFUSED_STREAM"); /** * 4 Unsupported Version */ public static final SpdyStreamStatus UNSUPPORTED_VERSION = new SpdyStreamStatus(4, "UNSUPPORTED_VERSION"); /** * 5 Cancel */ public static final SpdyStreamStatus CANCEL = new SpdyStreamStatus(5, "CANCEL"); /** * 6 Internal Error */ public static final SpdyStreamStatus INTERNAL_ERROR = new SpdyStreamStatus(6, "INTERNAL_ERROR"); /** * 7 Flow Control Error */ public static final SpdyStreamStatus FLOW_CONTROL_ERROR = new SpdyStreamStatus(7, "FLOW_CONTROL_ERROR"); /** * 8 Stream In Use */ public static final SpdyStreamStatus STREAM_IN_USE = new SpdyStreamStatus(8, "STREAM_IN_USE"); /** * 9 Stream Already Closed */ public static final SpdyStreamStatus STREAM_ALREADY_CLOSED = new SpdyStreamStatus(9, "STREAM_ALREADY_CLOSED"); /** * 10 Invalid Credentials */ public static final SpdyStreamStatus INVALID_CREDENTIALS = new SpdyStreamStatus(10, "INVALID_CREDENTIALS"); /** * 11 Frame Too Large */ public static final SpdyStreamStatus FRAME_TOO_LARGE = new SpdyStreamStatus(11, "FRAME_TOO_LARGE"); /** * Returns the {@link SpdyStreamStatus} represented by the specified code. * If the specified code is a defined SPDY status code, a cached instance * will be returned. Otherwise, a new instance will be returned. */ public static SpdyStreamStatus valueOf(int code) { if (code == 0) { throw new IllegalArgumentException( "0 is not a valid status code for a RST_STREAM"); } switch (code) { case 1: return PROTOCOL_ERROR; case 2: return INVALID_STREAM; case 3: return REFUSED_STREAM; case 4: return UNSUPPORTED_VERSION; case 5: return CANCEL; case 6: return INTERNAL_ERROR; case 7: return FLOW_CONTROL_ERROR; case 8: return STREAM_IN_USE; case 9: return STREAM_ALREADY_CLOSED; case 10: return INVALID_CREDENTIALS; case 11: return FRAME_TOO_LARGE; } return new SpdyStreamStatus(code, "UNKNOWN (" + code + ')'); } private final int code; private final String statusPhrase; /** * Creates a new instance with the specified {@code code} and its * {@code statusPhrase}. */ public SpdyStreamStatus(int code, String statusPhrase) { if (code == 0) { throw new IllegalArgumentException( "0 is not a valid status code for a RST_STREAM"); } if (statusPhrase == null) { throw new NullPointerException("statusPhrase"); } this.code = code; this.statusPhrase = statusPhrase; } /** * Returns the code of this status. */ public int getCode() { return code; } /** * Returns the status phrase of this status. */ public String getStatusPhrase() { return statusPhrase; } @Override public int hashCode() { return getCode(); } @Override public boolean equals(Object o) { if (!(o instanceof SpdyStreamStatus)) { return false; } return getCode() == ((SpdyStreamStatus) o).getCode(); } @Override public String toString() { return getStatusPhrase(); } public int compareTo(SpdyStreamStatus o) { return getCode() - o.getCode(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdySynReplyFrame.java000066400000000000000000000014501225554127700325130ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol SYN_REPLY Frame */ public interface SpdySynReplyFrame extends SpdyHeadersFrame { // Tag interface } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdySynStreamFrame.java000066400000000000000000000032011225554127700326470ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol SYN_STREAM Frame */ public interface SpdySynStreamFrame extends SpdyHeadersFrame { /** * Returns the Associated-To-Stream-ID of this frame. */ int getAssociatedToStreamId(); /** * Sets the Associated-To-Stream-ID of this frame. * The Associated-To-Stream-ID cannot be negative. */ void setAssociatedToStreamId(int associatedToStreamId); /** * Returns the priority of the stream. */ byte getPriority(); /** * Sets the priority of the stream. * The priority must be between 0 and 7 inclusive. */ void setPriority(byte priority); /** * Returns {@code true} if the stream created with this frame is to be * considered half-closed to the receiver. */ boolean isUnidirectional(); /** * Sets if the stream created with this frame is to be considered * half-closed to the receiver. */ void setUnidirectional(boolean unidirectional); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyVersion.java000066400000000000000000000024171225554127700314040ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; public enum SpdyVersion { SPDY_3 (3, 0, false), SPDY_3_1 (3, 1, true); private final int version; private final int minorVerison; private final boolean sessionFlowControl; private SpdyVersion(int version, int minorVersion, boolean sessionFlowControl) { this.version = version; this.minorVerison = minorVersion; this.sessionFlowControl = sessionFlowControl; } int getVersion() { return version; } int getMinorVersion() { return minorVerison; } boolean useSessionFlowControl() { return sessionFlowControl; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/SpdyWindowUpdateFrame.java000066400000000000000000000023571225554127700333470ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; /** * A SPDY Protocol WINDOW_UPDATE Frame */ public interface SpdyWindowUpdateFrame extends SpdyFrame { /** * Returns the Stream-ID of this frame. */ int getStreamId(); /** * Sets the Stream-ID of this frame. The Stream-ID cannot be negative. */ void setStreamId(int streamId); /** * Returns the Delta-Window-Size of this frame. */ int getDeltaWindowSize(); /** * Sets the Delta-Window-Size of this frame. * The Delta-Window-Size must be positive. */ void setDeltaWindowSize(int deltaWindowSize); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/spdy/package-info.java000066400000000000000000000020351225554127700314370ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder, decoder, session handler and their related message types for the SPDY protocol. * * @apiviz.exclude ^java\.lang\. * @apiviz.exclude OneToOne(Encoder|Decoder)$ * @apiviz.exclude \.SpdyHeaders\. * @apiviz.exclude \.codec\.frame\. * @apiviz.exclude \.(Simple)?Channel[A-Za-z]*Handler$ * @apiviz.exclude \.Default * @apiviz.exclude \.SpdyFrameCodec$ */ package org.jboss.netty.handler.codec.spdy; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/string/000077500000000000000000000000001225554127700265775ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/string/StringDecoder.java000066400000000000000000000063731225554127700322070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import java.nio.charset.Charset; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; /** * Decodes a received {@link ChannelBuffer} into a {@link String}. Please * note that this decoder must be used with a proper {@link FrameDecoder} * such as {@link DelimiterBasedFrameDecoder} if you are using a stream-based * transport such as TCP/IP. A typical setup for a text-based line protocol * in a TCP/IP socket would be: *
 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder", new {@link DelimiterBasedFrameDecoder}(80, {@link Delimiters#lineDelimiter()}));
 * pipeline.addLast("stringDecoder", new {@link StringDecoder}(CharsetUtil.UTF_8));
 *
 * // Encoder
 * pipeline.addLast("stringEncoder", new {@link StringEncoder}(CharsetUtil.UTF_8));
 * 
* and then you can use a {@link String} instead of a {@link ChannelBuffer} * as a message: *
 * void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     String msg = (String) e.getMessage();
 *     ch.write("Did you say '" + msg + "'?\n");
 * }
 * 
* * @apiviz.landmark */ @Sharable public class StringDecoder extends OneToOneDecoder { // TODO Use CharsetDecoder instead. private final Charset charset; /** * Creates a new instance with the current system character set. */ public StringDecoder() { this(Charset.defaultCharset()); } /** * Creates a new instance with the specified character set. */ public StringDecoder(Charset charset) { if (charset == null) { throw new NullPointerException("charset"); } this.charset = charset; } /** * @deprecated Use {@link #StringDecoder(Charset)} instead. */ @Deprecated public StringDecoder(String charsetName) { this(Charset.forName(charsetName)); } @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer)) { return msg; } return ((ChannelBuffer) msg).toString(charset); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/string/StringEncoder.java000066400000000000000000000062061225554127700322140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import java.nio.charset.Charset; import static org.jboss.netty.buffer.ChannelBuffers.*; /** * Encodes the requested {@link String} into a {@link ChannelBuffer}. * A typical setup for a text-based line protocol in a TCP/IP socket would be: *
 * {@link ChannelPipeline} pipeline = ...;
 *
 * // Decoders
 * pipeline.addLast("frameDecoder", new {@link DelimiterBasedFrameDecoder}({@link Delimiters#lineDelimiter()}));
 * pipeline.addLast("stringDecoder", new {@link StringDecoder}(CharsetUtil.UTF_8));
 *
 * // Encoder
 * pipeline.addLast("stringEncoder", new {@link StringEncoder}(CharsetUtil.UTF_8));
 * 
* and then you can use a {@link String} instead of a {@link ChannelBuffer} * as a message: *
 * void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     String msg = (String) e.getMessage();
 *     ch.write("Did you say '" + msg + "'?\n");
 * }
 * 
* * @apiviz.landmark */ @Sharable public class StringEncoder extends OneToOneEncoder { // TODO Use CharsetEncoder instead. private final Charset charset; /** * Creates a new instance with the current system character set. */ public StringEncoder() { this(Charset.defaultCharset()); } /** * Creates a new instance with the specified character set. */ public StringEncoder(Charset charset) { if (charset == null) { throw new NullPointerException("charset"); } this.charset = charset; } /** * @deprecated Use {@link #StringEncoder(Charset)} instead. */ @Deprecated public StringEncoder(String charsetName) { this(Charset.forName(charsetName)); } @Override protected Object encode( ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (msg instanceof String) { return copiedBuffer( ctx.getChannel().getConfig().getBufferFactory().getDefaultOrder(), (String) msg, charset); } return msg; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/codec/string/package-info.java000066400000000000000000000015341225554127700317710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Encoder and decoder which transform a {@link java.lang.String} into a * {@link org.jboss.netty.buffer.ChannelBuffer} and vice versa. * * @apiviz.exclude \.oneone\. */ package org.jboss.netty.handler.codec.string; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/000077500000000000000000000000001225554127700262175ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/ChainedExecutor.java000066400000000000000000000063731225554127700321450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import org.jboss.netty.util.ExternalResourceReleasable; /** * A special {@link Executor} which allows to chain a series of * {@link Executor}s and {@link ChannelEventRunnableFilter}. */ public class ChainedExecutor implements Executor, ExternalResourceReleasable { private final Executor cur; private final Executor next; private final ChannelEventRunnableFilter filter; /** * Create a new {@link ChainedExecutor} which will used the given * {@link ChannelEventRunnableFilter} to see if the {@link #cur} {@link Executor} should get * used. Otherwise it will pass the work to the {@link #next} {@link Executor} * * @param filter the {@link ChannelEventRunnableFilter} which will be used to check if the * {@link ChannelEventRunnable} should be passed to the cur or next {@link Executor} * @param cur the {@link Executor} to use if the {@link ChannelEventRunnableFilter} match * @param next the {@link Executor} to use if the {@link ChannelEventRunnableFilter} does not match */ public ChainedExecutor(ChannelEventRunnableFilter filter, Executor cur, Executor next) { if (filter == null) { throw new NullPointerException("filter"); } if (cur == null) { throw new NullPointerException("cur"); } if (next == null) { throw new NullPointerException("next"); } this.filter = filter; this.cur = cur; this.next = next; } /** * Execute the passed {@link ChannelEventRunnable} with the current {@link Executor} if the * {@link ChannelEventRunnableFilter} match. Otherwise pass it to the next {@link Executor} in * the chain. */ public void execute(Runnable command) { assert command instanceof ChannelEventRunnable; if (filter.filter((ChannelEventRunnable) command)) { cur.execute(command); } else { next.execute(command); } } public void releaseExternalResources() { if (cur instanceof ExecutorService) { ((ExecutorService) cur).shutdown(); } if (next instanceof ExecutorService) { ((ExecutorService) next).shutdown(); } releaseExternal(cur); releaseExternal(next); } private static void releaseExternal(Executor executor) { if (executor instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) executor).releaseExternalResources(); } } } ChannelDownstreamEventRunnable.java000066400000000000000000000024101225554127700351050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; /** * A {@link ChannelEventRunnable} which sends the specified {@link ChannelEvent} downstream. */ public class ChannelDownstreamEventRunnable extends ChannelEventRunnable { public ChannelDownstreamEventRunnable(ChannelHandlerContext ctx, ChannelEvent e, Executor executor) { super(ctx, e, executor); } /** * Send the {@link ChannelEvent} downstream */ @Override protected void doRun() { ctx.sendDownstream(e); } } ChannelDownstreamEventRunnableFilter.java000066400000000000000000000017671225554127700362710ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; /** * {@link ChannelEventRunnableFilter} implementation which matches {@link ChannelDownstreamEventRunnable} * */ public class ChannelDownstreamEventRunnableFilter implements ChannelEventRunnableFilter { public boolean filter(ChannelEventRunnable event) { return event instanceof ChannelDownstreamEventRunnable; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/ChannelEventRunnable.java000066400000000000000000000042371225554127700331310ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.util.EstimatableObjectWrapper; public abstract class ChannelEventRunnable implements Runnable, EstimatableObjectWrapper { /** * An internal use only thread-local variable that tells the * {@link Executor} that this worker acquired a worker thread from. */ protected static final ThreadLocal PARENT = new ThreadLocal(); protected final ChannelHandlerContext ctx; protected final ChannelEvent e; int estimatedSize; private final Executor executor; /** * Creates a {@link Runnable} which sends the specified {@link ChannelEvent} * upstream via the specified {@link ChannelHandlerContext}. */ protected ChannelEventRunnable(ChannelHandlerContext ctx, ChannelEvent e, Executor executor) { this.ctx = ctx; this.e = e; this.executor = executor; } /** * Returns the {@link ChannelHandlerContext} which will be used to * send the {@link ChannelEvent} upstream. */ public ChannelHandlerContext getContext() { return ctx; } /** * Returns the {@link ChannelEvent} which will be sent upstream. */ public ChannelEvent getEvent() { return e; } public Object unwrap() { return e; } public final void run() { doRun(); } protected abstract void doRun(); } ChannelEventRunnableFilter.java000066400000000000000000000016601225554127700342150ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import java.util.concurrent.Executor; public interface ChannelEventRunnableFilter { /** * Return {@code true} if the {@link ChannelEventRunnable} should get handled by the {@link Executor} * */ boolean filter(ChannelEventRunnable event); } ChannelUpstreamEventRunnable.java000066400000000000000000000027721225554127700345750ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; /** * A {@link ChannelEventRunnable} which sends the specified {@link ChannelEvent} upstream. * Most users will not see this type at all because it is used by * {@link Executor} implementers only */ public class ChannelUpstreamEventRunnable extends ChannelEventRunnable { /** * Creates a {@link Runnable} which sends the specified {@link ChannelEvent} * upstream via the specified {@link ChannelHandlerContext}. */ public ChannelUpstreamEventRunnable(ChannelHandlerContext ctx, ChannelEvent e, Executor executor) { super(ctx, e, executor); } /** * Sends the event upstream. */ @Override protected void doRun() { ctx.sendUpstream(e); } } ChannelUpstreamEventRunnableFilter.java000066400000000000000000000017421225554127700357370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; /** * {@link ChannelEventRunnableFilter} which matches {@link ChannelDownstreamEventRunnable} */ public class ChannelUpstreamEventRunnableFilter implements ChannelEventRunnableFilter { public boolean filter(ChannelEventRunnable event) { return event instanceof ChannelDownstreamEventRunnable; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/ExecutionHandler.java000066400000000000000000000175761225554127700323430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.Channels; import org.jboss.netty.util.ExternalResourceReleasable; /** * Forwards an upstream {@link ChannelEvent} to an {@link Executor}. *

* {@link ExecutionHandler} is often used when your {@link ChannelHandler} * performs a blocking operation that takes long time or accesses a resource * which is not CPU-bound business logic such as DB access. Running such * operations in a pipeline without an {@link ExecutionHandler} will result in * unwanted hiccup during I/O because an I/O thread cannot perform I/O until * your handler returns the control to the I/O thread. *

* In most cases, an {@link ExecutionHandler} is coupled with an * {@link OrderedMemoryAwareThreadPoolExecutor} because it guarantees the * correct event execution order and prevents an {@link OutOfMemoryError} * under load: *

 * public class DatabaseGatewayPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private final {@link ExecutionHandler} executionHandler;
 *
 *     public DatabaseGatewayPipelineFactory({@link ExecutionHandler} executionHandler) {
 *         this.executionHandler = executionHandler;
 *     }
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(
 *                 new DatabaseGatewayProtocolEncoder(),
 *                 new DatabaseGatewayProtocolDecoder(),
 *                 executionHandler, // Must be shared
 *                 new DatabaseQueryingHandler());
 *     }
 * }
 * ...
 *
 * public static void main(String[] args) {
 *     {@link ServerBootstrap} bootstrap = ...;
 *     ...
 *     {@link ExecutionHandler} executionHandler = new {@link ExecutionHandler}(
 *             new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576))
 *     bootstrap.setPipelineFactory(
 *             new DatabaseGatewayPipelineFactory(executionHandler));
 *     ...
 *     bootstrap.bind(...);
 *     ...
 *
 *     while (!isServerReadyToShutDown()) {
 *         // ... wait ...
 *     }
 *
 *     bootstrap.releaseExternalResources();
 *     executionHandler.releaseExternalResources();
 * }
 * 
* * Please refer to {@link OrderedMemoryAwareThreadPoolExecutor} for the * detailed information about how the event order is guaranteed. * *

SEDA (Staged Event-Driven Architecture)

* You can implement an alternative thread model such as * SEDA * by adding more than one {@link ExecutionHandler} to the pipeline. * *

Using other {@link Executor} implementation

* * Although it's recommended to use {@link OrderedMemoryAwareThreadPoolExecutor}, * you can use other {@link Executor} implementations. However, you must note * that other {@link Executor} implementation might break your application * because they often do not maintain event execution order nor interact with * I/O threads to control the incoming traffic and avoid {@link OutOfMemoryError}. * * @apiviz.landmark * @apiviz.has java.util.concurrent.ThreadPoolExecutor */ @Sharable public class ExecutionHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler, ExternalResourceReleasable { private final Executor executor; private final boolean handleDownstream; private final boolean handleUpstream; /** * Creates a new instance with the specified {@link Executor}. * Specify an {@link OrderedMemoryAwareThreadPoolExecutor} if unsure. */ public ExecutionHandler(Executor executor) { this(executor, false, true); } /** * Use {@link #ExecutionHandler(Executor, boolean, boolean)} * * {@link Deprecated} */ @Deprecated public ExecutionHandler(Executor executor, boolean handleDownstream) { this(executor, handleDownstream, true); } /** * Creates a new instance with the specified {@link Executor}. * Specify an {@link OrderedMemoryAwareThreadPoolExecutor} if unsure. */ public ExecutionHandler(Executor executor, boolean handleDownstream, boolean handleUpstream) { if (executor == null) { throw new NullPointerException("executor"); } if (!handleDownstream && !handleUpstream) { throw new IllegalArgumentException("You must handle at least handle one event type"); } this.executor = executor; this.handleDownstream = handleDownstream; this.handleUpstream = handleUpstream; } /** * Returns the {@link Executor} which was specified with the constructor. */ public Executor getExecutor() { return executor; } /** * Shuts down the {@link Executor} which was specified with the constructor * and wait for its termination. */ public void releaseExternalResources() { Executor executor = getExecutor(); if (executor instanceof ExecutorService) { ((ExecutorService) executor).shutdown(); } if (executor instanceof ExternalResourceReleasable) { ((ExternalResourceReleasable) executor).releaseExternalResources(); } } public void handleUpstream( ChannelHandlerContext context, ChannelEvent e) throws Exception { if (handleUpstream) { executor.execute(new ChannelUpstreamEventRunnable(context, e, executor)); } else { context.sendUpstream(e); } } public void handleDownstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { // check if the read was suspend if (!handleReadSuspend(ctx, e)) { if (handleDownstream) { executor.execute(new ChannelDownstreamEventRunnable(ctx, e, executor)); } else { ctx.sendDownstream(e); } } } /** * Handle suspended reads */ protected boolean handleReadSuspend(ChannelHandlerContext ctx, ChannelEvent e) { if (e instanceof ChannelStateEvent) { ChannelStateEvent cse = (ChannelStateEvent) e; if (cse.getState() == ChannelState.INTEREST_OPS && (((Integer) cse.getValue()).intValue() & Channel.OP_READ) != 0) { // setReadable(true) requested boolean readSuspended = ctx.getAttachment() != null; if (readSuspended) { // Drop the request silently if MemoryAwareThreadPool has // set the flag. e.getFuture().setSuccess(); return true; } } } return false; } } MemoryAwareThreadPoolExecutor.java000066400000000000000000000600701225554127700347370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.WriteCompletionEvent; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.DefaultObjectSizeEstimator; import org.jboss.netty.util.ObjectSizeEstimator; import org.jboss.netty.util.internal.ConcurrentIdentityHashMap; import org.jboss.netty.util.internal.SharedResourceMisuseDetector; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** * A {@link ThreadPoolExecutor} which blocks the task submission when there's * too many tasks in the queue. Both per-{@link Channel} and per-{@link Executor} * limitation can be applied. *

* When a task (i.e. {@link Runnable}) is submitted, * {@link MemoryAwareThreadPoolExecutor} calls {@link ObjectSizeEstimator#estimateSize(Object)} * to get the estimated size of the task in bytes to calculate the amount of * memory occupied by the unprocessed tasks. *

* If the total size of the unprocessed tasks exceeds either per-{@link Channel} * or per-{@link Executor} threshold, any further {@link #execute(Runnable)} * call will block until the tasks in the queue are processed so that the total * size goes under the threshold. * *

Using an alternative task size estimation strategy

* * Although the default implementation does its best to guess the size of an * object of unknown type, it is always good idea to to use an alternative * {@link ObjectSizeEstimator} implementation instead of the * {@link DefaultObjectSizeEstimator} to avoid incorrect task size calculation, * especially when: *
    *
  • you are using {@link MemoryAwareThreadPoolExecutor} independently from * {@link ExecutionHandler},
  • *
  • you are submitting a task whose type is not {@link ChannelEventRunnable}, or
  • *
  • the message type of the {@link MessageEvent} in the {@link ChannelEventRunnable} * is not {@link ChannelBuffer}.
  • *
* Here is an example that demonstrates how to implement an {@link ObjectSizeEstimator} * which understands a user-defined object: *
 * public class MyRunnable implements {@link Runnable} {
 *
 *     private final byte[] data;
 *
 *     public MyRunnable(byte[] data) {
 *         this.data = data;
 *     }
 *
 *     public void run() {
 *         // Process 'data' ..
 *     }
 * }
 *
 * public class MyObjectSizeEstimator extends {@link DefaultObjectSizeEstimator} {
 *
 *     {@literal @Override}
 *     public int estimateSize(Object o) {
 *         if (o instanceof MyRunnable) {
 *             return ((MyRunnable) o).data.length + 8;
 *         }
 *         return super.estimateSize(o);
 *     }
 * }
 *
 * {@link ThreadPoolExecutor} pool = new {@link MemoryAwareThreadPoolExecutor}(
 *         16, 65536, 1048576, 30, {@link TimeUnit}.SECONDS,
 *         new MyObjectSizeEstimator(),
 *         {@link Executors}.defaultThreadFactory());
 *
 * pool.execute(new MyRunnable(data));
 * 
* *

Event execution order

* * Please note that this executor does not maintain the order of the * {@link ChannelEvent}s for the same {@link Channel}. For example, * you can even receive a {@code "channelClosed"} event before a * {@code "messageReceived"} event, as depicted by the following diagram. * * For example, the events can be processed as depicted below: * *
 *           --------------------------------> Timeline -------------------------------->
 *
 * Thread X: --- Channel A (Event 1) --- Channel A (Event 2) --------------------------->
 *
 * Thread Y: --- Channel A (Event 3) --- Channel B (Event 2) --- Channel B (Event 3) --->
 *
 * Thread Z: --- Channel B (Event 1) --- Channel B (Event 4) --- Channel A (Event 4) --->
 * 
* * To maintain the event order, you must use {@link OrderedMemoryAwareThreadPoolExecutor}. * * @apiviz.has org.jboss.netty.util.ObjectSizeEstimator oneway - - * @apiviz.has org.jboss.netty.handler.execution.ChannelEventRunnable oneway - - executes */ public class MemoryAwareThreadPoolExecutor extends ThreadPoolExecutor { private static final InternalLogger logger = InternalLoggerFactory.getInstance(MemoryAwareThreadPoolExecutor.class); private static final SharedResourceMisuseDetector misuseDetector = new SharedResourceMisuseDetector(MemoryAwareThreadPoolExecutor.class); private volatile Settings settings; private final ConcurrentMap channelCounters = new ConcurrentIdentityHashMap(); private final Limiter totalLimiter; private volatile boolean notifyOnShutdown; /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. */ public MemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize) { this(corePoolSize, maxChannelMemorySize, maxTotalMemorySize, 30, TimeUnit.SECONDS); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} */ public MemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize, long keepAliveTime, TimeUnit unit) { this( corePoolSize, maxChannelMemorySize, maxTotalMemorySize, keepAliveTime, unit, Executors.defaultThreadFactory()); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} * @param threadFactory the {@link ThreadFactory} of this pool */ public MemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize, long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) { this( corePoolSize, maxChannelMemorySize, maxTotalMemorySize, keepAliveTime, unit, new DefaultObjectSizeEstimator(), threadFactory); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} * @param threadFactory the {@link ThreadFactory} of this pool * @param objectSizeEstimator the {@link ObjectSizeEstimator} of this pool */ public MemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize, long keepAliveTime, TimeUnit unit, ObjectSizeEstimator objectSizeEstimator, ThreadFactory threadFactory) { super(corePoolSize, corePoolSize, keepAliveTime, unit, new LinkedBlockingQueue(), threadFactory, new NewThreadRunsPolicy()); if (objectSizeEstimator == null) { throw new NullPointerException("objectSizeEstimator"); } if (maxChannelMemorySize < 0) { throw new IllegalArgumentException( "maxChannelMemorySize: " + maxChannelMemorySize); } if (maxTotalMemorySize < 0) { throw new IllegalArgumentException( "maxTotalMemorySize: " + maxTotalMemorySize); } // Call allowCoreThreadTimeOut(true) using reflection // because it is not supported in Java 5. try { Method m = getClass().getMethod("allowCoreThreadTimeOut", new Class[] { boolean.class }); m.invoke(this, Boolean.TRUE); } catch (Throwable t) { // Java 5 logger.debug( "ThreadPoolExecutor.allowCoreThreadTimeOut() is not " + "supported in this platform."); } settings = new Settings( objectSizeEstimator, maxChannelMemorySize); if (maxTotalMemorySize == 0) { totalLimiter = null; } else { totalLimiter = new Limiter(maxTotalMemorySize); } // Misuse check misuseDetector.increase(); } @Override protected void terminated() { super.terminated(); misuseDetector.decrease(); } /** * This will call {@link #shutdownNow(boolean)} with the value of {@link #getNotifyChannelFuturesOnShutdown()}. */ @Override public List shutdownNow() { return shutdownNow(notifyOnShutdown); } /** * See {@link ThreadPoolExecutor#shutdownNow()} for how it handles the shutdown. * If {@code true} is given to this method it also notifies all {@link ChannelFuture}'s * of the not executed {@link ChannelEventRunnable}'s. * *

* Be aware that if you call this with {@code false} you will need to handle the * notification of the {@link ChannelFuture}'s by your self. So only use this if you * really have a use-case for it. *

* */ public List shutdownNow(boolean notify) { if (!notify) { return super.shutdownNow(); } Throwable cause = null; Set channels = null; List tasks = super.shutdownNow(); // loop over all tasks and cancel the ChannelFuture of the ChannelEventRunable's for (Runnable task: tasks) { if (task instanceof ChannelEventRunnable) { if (cause == null) { cause = new IOException("Unable to process queued event"); } ChannelEvent event = ((ChannelEventRunnable) task).getEvent(); event.getFuture().setFailure(cause); if (channels == null) { channels = new HashSet(); } // store the Channel of the event for later notification of the exceptionCaught event channels.add(event.getChannel()); } } // loop over all channels and fire an exceptionCaught event if (channels != null) { for (Channel channel: channels) { Channels.fireExceptionCaughtLater(channel, cause); } } return tasks; } /** * Returns the {@link ObjectSizeEstimator} of this pool. */ public ObjectSizeEstimator getObjectSizeEstimator() { return settings.objectSizeEstimator; } /** * Sets the {@link ObjectSizeEstimator} of this pool. */ public void setObjectSizeEstimator(ObjectSizeEstimator objectSizeEstimator) { if (objectSizeEstimator == null) { throw new NullPointerException("objectSizeEstimator"); } settings = new Settings( objectSizeEstimator, settings.maxChannelMemorySize); } /** * Returns the maximum total size of the queued events per channel. */ public long getMaxChannelMemorySize() { return settings.maxChannelMemorySize; } /** * Sets the maximum total size of the queued events per channel. * Specify {@code 0} to disable. */ public void setMaxChannelMemorySize(long maxChannelMemorySize) { if (maxChannelMemorySize < 0) { throw new IllegalArgumentException( "maxChannelMemorySize: " + maxChannelMemorySize); } if (getTaskCount() > 0) { throw new IllegalStateException( "can't be changed after a task is executed"); } settings = new Settings( settings.objectSizeEstimator, maxChannelMemorySize); } /** * Returns the maximum total size of the queued events for this pool. */ public long getMaxTotalMemorySize() { if (totalLimiter == null) { return 0; } return totalLimiter.limit; } /** * @deprecated maxTotalMemorySize is not modifiable anymore. */ @Deprecated public void setMaxTotalMemorySize(long maxTotalMemorySize) { if (maxTotalMemorySize < 0) { throw new IllegalArgumentException( "maxTotalMemorySize: " + maxTotalMemorySize); } if (getTaskCount() > 0) { throw new IllegalStateException( "can't be changed after a task is executed"); } } /** * If set to {@code false} no queued {@link ChannelEventRunnable}'s {@link ChannelFuture} * will get notified once {@link #shutdownNow()} is called. If set to {@code true} every * queued {@link ChannelEventRunnable} will get marked as failed via {@link ChannelFuture#setFailure(Throwable)}. * *

* Please only set this to {@code false} if you want to handle the notification by yourself * and know what you are doing. Default is {@code true}. *

*/ public void setNotifyChannelFuturesOnShutdown(boolean notifyOnShutdown) { this.notifyOnShutdown = notifyOnShutdown; } /** * Returns if the {@link ChannelFuture}'s of the {@link ChannelEventRunnable}'s should be * notified about the shutdown of this {@link MemoryAwareThreadPoolExecutor}. */ public boolean getNotifyChannelFuturesOnShutdown() { return notifyOnShutdown; } @Override public void execute(Runnable command) { if (command instanceof ChannelDownstreamEventRunnable) { throw new RejectedExecutionException("command must be enclosed with an upstream event."); } if (!(command instanceof ChannelEventRunnable)) { command = new MemoryAwareRunnable(command); } increaseCounter(command); doExecute(command); } /** * Put the actual execution logic here. The default implementation simply * calls {@link #doUnorderedExecute(Runnable)}. */ protected void doExecute(Runnable task) { doUnorderedExecute(task); } /** * Executes the specified task without maintaining the event order. */ protected final void doUnorderedExecute(Runnable task) { super.execute(task); } @Override public boolean remove(Runnable task) { boolean removed = super.remove(task); if (removed) { decreaseCounter(task); } return removed; } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); decreaseCounter(r); } protected void increaseCounter(Runnable task) { if (!shouldCount(task)) { return; } Settings settings = this.settings; long maxChannelMemorySize = settings.maxChannelMemorySize; int increment = settings.objectSizeEstimator.estimateSize(task); if (task instanceof ChannelEventRunnable) { ChannelEventRunnable eventTask = (ChannelEventRunnable) task; eventTask.estimatedSize = increment; Channel channel = eventTask.getEvent().getChannel(); long channelCounter = getChannelCounter(channel).addAndGet(increment); //System.out.println("IC: " + channelCounter + ", " + increment); if (maxChannelMemorySize != 0 && channelCounter >= maxChannelMemorySize && channel.isOpen()) { if (channel.isReadable()) { //System.out.println("UNREADABLE"); ChannelHandlerContext ctx = eventTask.getContext(); if (ctx.getHandler() instanceof ExecutionHandler) { // readSuspended = true; ctx.setAttachment(Boolean.TRUE); } channel.setReadable(false); } } } else { ((MemoryAwareRunnable) task).estimatedSize = increment; } if (totalLimiter != null) { totalLimiter.increase(increment); } } protected void decreaseCounter(Runnable task) { if (!shouldCount(task)) { return; } Settings settings = this.settings; long maxChannelMemorySize = settings.maxChannelMemorySize; int increment; if (task instanceof ChannelEventRunnable) { increment = ((ChannelEventRunnable) task).estimatedSize; } else { increment = ((MemoryAwareRunnable) task).estimatedSize; } if (totalLimiter != null) { totalLimiter.decrease(increment); } if (task instanceof ChannelEventRunnable) { ChannelEventRunnable eventTask = (ChannelEventRunnable) task; Channel channel = eventTask.getEvent().getChannel(); long channelCounter = getChannelCounter(channel).addAndGet(-increment); //System.out.println("DC: " + channelCounter + ", " + increment); if (maxChannelMemorySize != 0 && channelCounter < maxChannelMemorySize && channel.isOpen()) { if (!channel.isReadable()) { //System.out.println("READABLE"); ChannelHandlerContext ctx = eventTask.getContext(); if (ctx.getHandler() instanceof ExecutionHandler) { // check if the attachment was set as this means that we suspend the channel // from reads. This only works when this pool is used with ExecutionHandler // but I guess thats good enough for us. // // See #215 if (ctx.getAttachment() != null) { // readSuspended = false; ctx.setAttachment(null); channel.setReadable(true); } } else { channel.setReadable(true); } } } } } private AtomicLong getChannelCounter(Channel channel) { AtomicLong counter = channelCounters.get(channel); if (counter == null) { counter = new AtomicLong(); AtomicLong oldCounter = channelCounters.putIfAbsent(channel, counter); if (oldCounter != null) { counter = oldCounter; } } // Remove the entry when the channel closes. if (!channel.isOpen()) { channelCounters.remove(channel); } return counter; } /** * Returns {@code true} if and only if the specified {@code task} should * be counted to limit the global and per-channel memory consumption. * To override this method, you must call {@code super.shouldCount()} to * make sure important tasks are not counted. */ protected boolean shouldCount(Runnable task) { if (task instanceof ChannelUpstreamEventRunnable) { ChannelUpstreamEventRunnable r = (ChannelUpstreamEventRunnable) task; ChannelEvent e = r.getEvent(); if (e instanceof WriteCompletionEvent) { return false; } else if (e instanceof ChannelStateEvent) { if (((ChannelStateEvent) e).getState() == ChannelState.INTEREST_OPS) { return false; } } } return true; } private static final class Settings { final ObjectSizeEstimator objectSizeEstimator; final long maxChannelMemorySize; Settings(ObjectSizeEstimator objectSizeEstimator, long maxChannelMemorySize) { this.objectSizeEstimator = objectSizeEstimator; this.maxChannelMemorySize = maxChannelMemorySize; } } private static final class NewThreadRunsPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { final Thread t = new Thread(r, "Temporary task executor"); t.start(); } catch (Throwable e) { throw new RejectedExecutionException( "Failed to start a new thread", e); } } } private static final class MemoryAwareRunnable implements Runnable { final Runnable task; int estimatedSize; MemoryAwareRunnable(Runnable task) { this.task = task; } public void run() { task.run(); } } private static class Limiter { final long limit; private long counter; private int waiters; Limiter(long limit) { this.limit = limit; } synchronized void increase(long amount) { while (counter >= limit) { waiters ++; try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { waiters --; } } counter += amount; } synchronized void decrease(long amount) { counter -= amount; if (counter < limit && waiters > 0) { notifyAll(); } } } } OrderedDownstreamThreadPoolExecutor.java000066400000000000000000000133151225554127700361370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.util.ObjectSizeEstimator; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * {@link Executor} which should be used for downstream {@link ChannelEvent}'s. This implementation * will take care of preserve the order of the events in a {@link Channel}. If you don't need to * preserve the order just use one of the {@link Executor} implementations provided by the static * methods of {@link Executors}. *
*
* For more informations about how the order is preserved see {@link OrderedMemoryAwareThreadPoolExecutor} */ public final class OrderedDownstreamThreadPoolExecutor extends OrderedMemoryAwareThreadPoolExecutor { /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads */ public OrderedDownstreamThreadPoolExecutor(int corePoolSize) { super(corePoolSize, 0L, 0L); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} */ public OrderedDownstreamThreadPoolExecutor( int corePoolSize, long keepAliveTime, TimeUnit unit) { super(corePoolSize, 0L, 0L, keepAliveTime, unit); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} * @param threadFactory the {@link ThreadFactory} of this pool */ public OrderedDownstreamThreadPoolExecutor( int corePoolSize, long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) { super(corePoolSize, 0L, 0L, keepAliveTime, unit, threadFactory); } /** * Return {@code null} */ @Override public ObjectSizeEstimator getObjectSizeEstimator() { return null; } /** * Throws {@link UnsupportedOperationException} as there is not support for limit the memory * size in this implementation */ @Override public void setObjectSizeEstimator(ObjectSizeEstimator objectSizeEstimator) { throw new UnsupportedOperationException("Not supported by this implementation"); } /** * Returns {@code 0L} */ @Override public long getMaxChannelMemorySize() { return 0L; } /** * Throws {@link UnsupportedOperationException} as there is not support for limit the memory * size in this implementation */ @Override public void setMaxChannelMemorySize(long maxChannelMemorySize) { throw new UnsupportedOperationException("Not supported by this implementation"); } /** * Returns {@code 0L} */ @Override public long getMaxTotalMemorySize() { return 0L; } /** * Throws {@link UnsupportedOperationException} as there is not support for limit the memory * size in this implementation */ @Override @Deprecated public void setMaxTotalMemorySize(long maxTotalMemorySize) { throw new UnsupportedOperationException("Not supported by this implementation"); } /** * Return {@code false} as we not need to cound the memory in this implementation */ @Override protected boolean shouldCount(Runnable task) { return false; } @Override public void execute(Runnable command) { // check if the Runnable was of an unsupported type if (command instanceof ChannelUpstreamEventRunnable) { throw new RejectedExecutionException("command must be enclosed with an downstream event."); } doExecute(command); } @Override protected Executor getChildExecutor(ChannelEvent e) { final Object key = getChildExecutorKey(e); Executor executor = childExecutors.get(key); if (executor == null) { executor = new ChildExecutor(); Executor oldExecutor = childExecutors.putIfAbsent(key, executor); if (oldExecutor != null) { executor = oldExecutor; } else { // register a listener so that the ChildExecutor will get removed once the channel was closed e.getChannel().getCloseFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { removeChildExecutor(key); } }); } } return executor; } } OrderedMemoryAwareThreadPoolExecutor.java000066400000000000000000000333721225554127700362510ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.util.ObjectSizeEstimator; import org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap; import java.util.IdentityHashMap; import java.util.Queue; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * A {@link MemoryAwareThreadPoolExecutor} which makes sure the events from the * same {@link Channel} are executed sequentially. *

* NOTE: This thread pool inherits most characteristics of its super * type, so please make sure to refer to {@link MemoryAwareThreadPoolExecutor} * to understand how it works basically. * *

Event execution order

* * For example, let's say there are two executor threads that handle the events * from the two channels: *
 *           -------------------------------------> Timeline ------------------------------------>
 *
 * Thread X: --- Channel A (Event A1) --.   .-- Channel B (Event B2) --- Channel B (Event B3) --->
 *                                      \ /
 *                                       X
 *                                      / \
 * Thread Y: --- Channel B (Event B1) --'   '-- Channel A (Event A2) --- Channel A (Event A3) --->
 * 
* As you see, the events from different channels are independent from each * other. That is, an event of Channel B will not be blocked by an event of * Channel A and vice versa, unless the thread pool is exhausted. *

* Also, it is guaranteed that the invocation will be made sequentially for the * events from the same channel. For example, the event A2 is never executed * before the event A1 is finished. (Although not recommended, if you want the * events from the same channel to be executed simultaneously, please use * {@link MemoryAwareThreadPoolExecutor} instead.) *

* However, it is not guaranteed that the invocation will be made by the same * thread for the same channel. The events from the same channel can be * executed by different threads. For example, the Event A2 is executed by the * thread Y while the event A1 was executed by the thread X. * *

Using a different key other than {@link Channel} to maintain event order

*

* {@link OrderedMemoryAwareThreadPoolExecutor} uses a {@link Channel} as a key * that is used for maintaining the event execution order, as explained in the * previous section. Alternatively, you can extend it to change its behavior. * For example, you can change the key to the remote IP of the peer: * *

 * public class RemoteAddressBasedOMATPE extends {@link OrderedMemoryAwareThreadPoolExecutor} {
 *
 *     ... Constructors ...
 *
 *     {@code @Override}
 *     protected ConcurrentMap<Object, Executor> newChildExecutorMap() {
 *         // The default implementation returns a special ConcurrentMap that
 *         // uses identity comparison only (see {@link IdentityHashMap}).
 *         // Because SocketAddress does not work with identity comparison,
 *         // we need to employ more generic implementation.
 *         return new ConcurrentHashMap<Object, Executor>
 *     }
 *
 *     protected Object getChildExecutorKey({@link ChannelEvent} e) {
 *         // Use the IP of the remote peer as a key.
 *         return ((InetSocketAddress) e.getChannel().getRemoteAddress()).getAddress();
 *     }
 *
 *     // Make public so that you can call from anywhere.
 *     public boolean removeChildExecutor(Object key) {
 *         super.removeChildExecutor(key);
 *     }
 * }
 * 
* * Please be very careful of memory leak of the child executor map. You must * call {@link #removeChildExecutor(Object)} when the life cycle of the key * ends (e.g. all connections from the same IP were closed.) Also, please * keep in mind that the key can appear again after calling {@link #removeChildExecutor(Object)} * (e.g. a new connection could come in from the same old IP after removal.) * If in doubt, prune the old unused or stall keys from the child executor map * periodically: * *
 * RemoteAddressBasedOMATPE executor = ...;
 *
 * on every 3 seconds:
 *
 *   for (Iterator<Object> i = executor.getChildExecutorKeySet().iterator; i.hasNext();) {
 *       InetAddress ip = (InetAddress) i.next();
 *       if (there is no active connection from 'ip' now &&
 *           there has been no incoming connection from 'ip' for last 10 minutes) {
 *           i.remove();
 *       }
 *   }
 * 
* * If the expected maximum number of keys is small and deterministic, you could * use a weak key map such as ConcurrentWeakHashMap * or synchronized {@link WeakHashMap} instead of managing the life cycle of the * keys by yourself. * * @apiviz.landmark */ public class OrderedMemoryAwareThreadPoolExecutor extends MemoryAwareThreadPoolExecutor { // TODO Make OMATPE focus on the case where Channel is the key. // Add a new less-efficient TPE that allows custom key. protected final ConcurrentMap childExecutors = newChildExecutorMap(); /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. */ public OrderedMemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize) { super(corePoolSize, maxChannelMemorySize, maxTotalMemorySize); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} */ public OrderedMemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize, long keepAliveTime, TimeUnit unit) { super(corePoolSize, maxChannelMemorySize, maxTotalMemorySize, keepAliveTime, unit); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} * @param threadFactory the {@link ThreadFactory} of this pool */ public OrderedMemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize, long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) { super(corePoolSize, maxChannelMemorySize, maxTotalMemorySize, keepAliveTime, unit, threadFactory); } /** * Creates a new instance. * * @param corePoolSize the maximum number of active threads * @param maxChannelMemorySize the maximum total size of the queued events per channel. * Specify {@code 0} to disable. * @param maxTotalMemorySize the maximum total size of the queued events for this pool * Specify {@code 0} to disable. * @param keepAliveTime the amount of time for an inactive thread to shut itself down * @param unit the {@link TimeUnit} of {@code keepAliveTime} * @param threadFactory the {@link ThreadFactory} of this pool * @param objectSizeEstimator the {@link ObjectSizeEstimator} of this pool */ public OrderedMemoryAwareThreadPoolExecutor( int corePoolSize, long maxChannelMemorySize, long maxTotalMemorySize, long keepAliveTime, TimeUnit unit, ObjectSizeEstimator objectSizeEstimator, ThreadFactory threadFactory) { super(corePoolSize, maxChannelMemorySize, maxTotalMemorySize, keepAliveTime, unit, objectSizeEstimator, threadFactory); } protected ConcurrentMap newChildExecutorMap() { return new ConcurrentIdentityWeakKeyHashMap(); } protected Object getChildExecutorKey(ChannelEvent e) { return e.getChannel(); } protected Set getChildExecutorKeySet() { return childExecutors.keySet(); } protected boolean removeChildExecutor(Object key) { // FIXME: Succeed only when there is no task in the ChildExecutor's queue. // Note that it will need locking which might slow down task submission. return childExecutors.remove(key) != null; } /** * Executes the specified task concurrently while maintaining the event * order. */ @Override protected void doExecute(Runnable task) { if (!(task instanceof ChannelEventRunnable)) { doUnorderedExecute(task); } else { ChannelEventRunnable r = (ChannelEventRunnable) task; getChildExecutor(r.getEvent()).execute(task); } } protected Executor getChildExecutor(ChannelEvent e) { Object key = getChildExecutorKey(e); Executor executor = childExecutors.get(key); if (executor == null) { executor = new ChildExecutor(); Executor oldExecutor = childExecutors.putIfAbsent(key, executor); if (oldExecutor != null) { executor = oldExecutor; } } // Remove the entry when the channel closes. if (e instanceof ChannelStateEvent) { Channel channel = e.getChannel(); ChannelStateEvent se = (ChannelStateEvent) e; if (se.getState() == ChannelState.OPEN && !channel.isOpen()) { removeChildExecutor(key); } } return executor; } @Override protected boolean shouldCount(Runnable task) { if (task instanceof ChildExecutor) { return false; } return super.shouldCount(task); } void onAfterExecute(Runnable r, Throwable t) { afterExecute(r, t); } protected final class ChildExecutor implements Executor, Runnable { private final Queue tasks = new ConcurrentLinkedQueue(); private final AtomicBoolean isRunning = new AtomicBoolean(); public void execute(Runnable command) { // TODO: What todo if the add return false ? tasks.add(command); if (!isRunning.get()) { doUnorderedExecute(this); } } public void run() { boolean acquired; // check if its already running by using CAS. If so just return here. So in the worst case the thread // is executed and do nothing if (isRunning.compareAndSet(false, true)) { acquired = true; try { Thread thread = Thread.currentThread(); for (;;) { final Runnable task = tasks.poll(); // if the task is null we should exit the loop if (task == null) { break; } boolean ran = false; beforeExecute(thread, task); try { task.run(); ran = true; onAfterExecute(task, null); } catch (RuntimeException e) { if (!ran) { onAfterExecute(task, e); } throw e; } } } finally { // set it back to not running isRunning.set(false); } if (acquired && !isRunning.get() && tasks.peek() != null) { doUnorderedExecute(this); } } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/execution/package-info.java000066400000000000000000000017571225554127700314200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * {@link java.util.concurrent.Executor}-based implementation of various * thread models that separate business logic from I/O threads * * @apiviz.exclude ^java\.lang\. * @apiviz.exclude \.netty\.channel\. * @apiviz.exclude \.ExternalResourceReleasable$ * @apiviz.exclude \.Channel[A-Za-z]*EventRunnable[A-Za-z]*$ */ package org.jboss.netty.handler.execution; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/000077500000000000000000000000001225554127700260325ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/CIDR.java000066400000000000000000000167421225554127700274300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.StringTokenizer; /** */ public abstract class CIDR implements Comparable { /** The base address of the CIDR notation */ protected InetAddress baseAddress; /** The mask used in the CIDR notation */ protected int cidrMask; /** * Create CIDR using the CIDR Notation * * @return the generated CIDR */ public static CIDR newCIDR(InetAddress baseAddress, int cidrMask) throws UnknownHostException { if (cidrMask < 0) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } if (baseAddress instanceof Inet4Address) { if (cidrMask > 32) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR4((Inet4Address) baseAddress, cidrMask); } // IPv6. if (cidrMask > 128) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR6((Inet6Address) baseAddress, cidrMask); } /** * Create CIDR using the normal Notation * * @return the generated CIDR */ public static CIDR newCIDR(InetAddress baseAddress, String scidrMask) throws UnknownHostException { int cidrMask = getNetMask(scidrMask); if (cidrMask < 0) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } if (baseAddress instanceof Inet4Address) { if (cidrMask > 32) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR4((Inet4Address) baseAddress, cidrMask); } cidrMask += 96; // IPv6. if (cidrMask > 128) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR6((Inet6Address) baseAddress, cidrMask); } /** * Create CIDR using the CIDR or normal Notation
* i.e.: * CIDR subnet = newCIDR ("10.10.10.0/24"); or * CIDR subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or * CIDR subnet = newCIDR ("10.10.10.0/255.255.255.0"); * * @return the generated CIDR */ public static CIDR newCIDR(String cidr) throws UnknownHostException { int p = cidr.indexOf('/'); if (p < 0) { throw new UnknownHostException("Invalid CIDR notation used: " + cidr); } String addrString = cidr.substring(0, p); String maskString = cidr.substring(p + 1); InetAddress addr = addressStringToInet(addrString); int mask; if (maskString.indexOf('.') < 0) { mask = parseInt(maskString, -1); } else { mask = getNetMask(maskString); if (addr instanceof Inet6Address) { mask += 96; } } if (mask < 0) { throw new UnknownHostException("Invalid mask length used: " + maskString); } return newCIDR(addr, mask); } /** @return the baseAddress of the CIDR block. */ public InetAddress getBaseAddress() { return baseAddress; } /** @return the Mask length. */ public int getMask() { return cidrMask; } /** @return the textual CIDR notation. */ @Override public String toString() { return baseAddress.getHostAddress() + '/' + cidrMask; } /** @return the end address of this block. */ public abstract InetAddress getEndAddress(); /** * Compares the given InetAddress against the CIDR and returns true if * the ip is in the subnet-ip-range and false if not. * * @return returns true if the given IP address is inside the currently * set network. */ public abstract boolean contains(InetAddress inetAddress); @Override public boolean equals(Object o) { if (!(o instanceof CIDR)) { return false; } return compareTo((CIDR) o) == 0; } @Override public int hashCode() { return baseAddress.hashCode(); } /** * Convert an IPv4 or IPv6 textual representation into an * InetAddress. * * @return the created InetAddress */ private static InetAddress addressStringToInet(String addr) throws UnknownHostException { return InetAddress.getByName(addr); } /** * Get the Subnet's Netmask in Decimal format.
* i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask * * @param netMask a network mask * @return the integer CIDR mask */ private static int getNetMask(String netMask) { StringTokenizer nm = new StringTokenizer(netMask, "."); int i = 0; int[] netmask = new int[4]; while (nm.hasMoreTokens()) { netmask[i] = Integer.parseInt(nm.nextToken()); i++; } int mask1 = 0; for (i = 0; i < 4; i++) { mask1 += Integer.bitCount(netmask[i]); } return mask1; } /** * @param intstr a string containing an integer. * @param def the default if the string does not contain a valid * integer. * @return the inetAddress from the integer */ private static int parseInt(String intstr, int def) { Integer res; if (intstr == null) { return def; } try { res = Integer.decode(intstr); } catch (Exception e) { res = def; } return res.intValue(); } /** * Compute a byte representation of IpV4 from a IpV6 * * @return the byte representation * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 */ public static byte[] getIpV4FromIpV6(Inet6Address address) { byte[] baddr = address.getAddress(); for (int i = 0; i < 9; i++) { if (baddr[i] != 0) { throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); } } if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF) { throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); } return new byte[] {baddr[12], baddr[13], baddr[14], baddr[15]}; } /** * Compute a byte representation of IpV6 from a IpV4 * * @return the byte representation * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 */ public static byte[] getIpV6FromIpV4(Inet4Address address) { byte[] baddr = address.getAddress(); return new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]}; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/CIDR4.java000066400000000000000000000114741225554127700275110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; /** */ public class CIDR4 extends CIDR { /** The integer for the base address */ private int addressInt; /** The integer for the end address */ private final int addressEndInt; protected CIDR4(Inet4Address newaddr, int mask) { cidrMask = mask; addressInt = ipv4AddressToInt(newaddr); int newmask = ipv4PrefixLengthToMask(mask); addressInt &= newmask; try { baseAddress = intToIPv4Address(addressInt); } catch (UnknownHostException e) { // this should never happen } addressEndInt = addressInt + ipv4PrefixLengthToLength(cidrMask) - 1; } @Override public InetAddress getEndAddress() { try { return intToIPv4Address(addressEndInt); } catch (UnknownHostException e) { // this should never happen return null; } } public int compareTo(CIDR arg) { if (arg instanceof CIDR6) { byte[] address = getIpV4FromIpV6((Inet6Address) arg.baseAddress); int net = ipv4AddressToInt(address); if (net == addressInt && arg.cidrMask == cidrMask) { return 0; } if (net < addressInt) { return 1; } if (net > addressInt) { return -1; } if (arg.cidrMask < cidrMask) { return -1; } return 1; } CIDR4 o = (CIDR4) arg; if (o.addressInt == addressInt && o.cidrMask == cidrMask) { return 0; } if (o.addressInt < addressInt) { return 1; } if (o.addressInt > addressInt) { return -1; } if (o.cidrMask < cidrMask) { // greater Mask means less IpAddresses so -1 return -1; } return 1; } @Override public boolean contains(InetAddress inetAddress) { int search = ipv4AddressToInt(inetAddress); return search >= addressInt && search <= addressEndInt; } /** * Given an IPv4 baseAddress length, return the block length. I.e., a * baseAddress length of 24 will return 256. */ private static int ipv4PrefixLengthToLength(int prefixLength) { return 1 << 32 - prefixLength; } /** * Given a baseAddress length, return a netmask. I.e, a baseAddress length * of 24 will return 0xFFFFFF00. */ private static int ipv4PrefixLengthToMask(int prefixLength) { return ~((1 << 32 - prefixLength) - 1); } /** * Convert an integer into an (IPv4) InetAddress. * * @return the created InetAddress */ private static InetAddress intToIPv4Address(int addr) throws UnknownHostException { byte[] a = new byte[4]; a[0] = (byte) (addr >> 24 & 0xFF); a[1] = (byte) (addr >> 16 & 0xFF); a[2] = (byte) (addr >> 8 & 0xFF); a[3] = (byte) (addr & 0xFF); return InetAddress.getByAddress(a); } /** * Given an IPv4 address, convert it into an integer. * * @return the integer representation of the InetAddress * @throws IllegalArgumentException if the address is really an * IPv6 address. */ private static int ipv4AddressToInt(InetAddress addr) { byte[] address; if (addr instanceof Inet6Address) { address = getIpV4FromIpV6((Inet6Address) addr); } else { address = addr.getAddress(); } return ipv4AddressToInt(address); } /** * Given an IPv4 address as array of bytes, convert it into an integer. * * @return the integer representation of the InetAddress * @throws IllegalArgumentException if the address is really an * IPv6 address. */ private static int ipv4AddressToInt(byte[] address) { int net = 0; for (byte addres : address) { net <<= 8; net |= addres & 0xFF; } return net; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/CIDR6.java000066400000000000000000000125041225554127700275060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; /** */ public class CIDR6 extends CIDR { private static final InternalLogger logger = InternalLoggerFactory.getInstance(CIDR6.class); /** The big integer for the base address */ private BigInteger addressBigInt; /** The big integer for the end address */ private final BigInteger addressEndBigInt; protected CIDR6(Inet6Address newaddress, int newmask) { cidrMask = newmask; addressBigInt = ipv6AddressToBigInteger(newaddress); BigInteger mask = ipv6CidrMaskToMask(newmask); try { addressBigInt = addressBigInt.and(mask); baseAddress = bigIntToIPv6Address(addressBigInt); } catch (UnknownHostException e) { // this should never happen. } addressEndBigInt = addressBigInt.add(ipv6CidrMaskToBaseAddress(cidrMask)).subtract(BigInteger.ONE); } @Override public InetAddress getEndAddress() { try { return bigIntToIPv6Address(addressEndBigInt); } catch (UnknownHostException e) { if (logger.isErrorEnabled()) { logger.error("invalid ip address calculated as an end address"); } return null; } } public int compareTo(CIDR arg) { if (arg instanceof CIDR4) { BigInteger net = ipv6AddressToBigInteger(arg.baseAddress); int res = net.compareTo(addressBigInt); if (res == 0) { if (arg.cidrMask == cidrMask) { return 0; } if (arg.cidrMask < cidrMask) { return -1; } return 1; } return res; } CIDR6 o = (CIDR6) arg; if (o.addressBigInt.equals(addressBigInt) && o.cidrMask == cidrMask) { return 0; } int res = o.addressBigInt.compareTo(addressBigInt); if (res == 0) { if (o.cidrMask < cidrMask) { // greater Mask means less IpAddresses so -1 return -1; } return 1; } return res; } @Override public boolean contains(InetAddress inetAddress) { BigInteger search = ipv6AddressToBigInteger(inetAddress); return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0; } /** * Given an IPv6 baseAddress length, return the block length. I.e., a * baseAddress length of 96 will return 2**32. */ private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask) { return BigInteger.ONE.shiftLeft(128 - cidrMask); } private static BigInteger ipv6CidrMaskToMask(int cidrMask) { return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not(); } /** * Given an IPv6 address, convert it into a BigInteger. * * @return the integer representation of the InetAddress * @throws IllegalArgumentException if the address is not an IPv6 * address. */ private static BigInteger ipv6AddressToBigInteger(InetAddress addr) { byte[] ipv6; if (addr instanceof Inet4Address) { ipv6 = getIpV6FromIpV4((Inet4Address) addr); } else { ipv6 = addr.getAddress(); } if (ipv6[0] == -1) { return new BigInteger(1, ipv6); } return new BigInteger(ipv6); } /** * Convert a big integer into an IPv6 address. * * @return the inetAddress from the integer * @throws UnknownHostException if the big integer is too large, * and thus an invalid IPv6 address. */ private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException { byte[] a = new byte[16]; byte[] b = addr.toByteArray(); if (b.length > 16 && !(b.length == 17 && b[0] == 0)) { throw new UnknownHostException("invalid IPv6 address (too big)"); } if (b.length == 16) { return InetAddress.getByAddress(b); } // handle the case where the IPv6 address starts with "FF". if (b.length == 17) { System.arraycopy(b, 1, a, 0, 16); } else { // copy the address into a 16 byte array, zero-filled. int p = 16 - b.length; System.arraycopy(b, 0, a, p, b.length); } return InetAddress.getByAddress(a); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterListener.java000066400000000000000000000063321225554127700321250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.InetSocketAddress; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; /** * The listener interface for receiving ipFilter events. * * @see IpFilteringHandler */ public interface IpFilterListener { /** * Called when the channel has the CONNECTED status and the channel was allowed by a previous call to accept(). * This method enables your implementation to send a message back to the client before closing * or whatever you need. This method returns a ChannelFuture on which the implementation * can wait uninterruptibly before continuing.
* For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. * * @param inetSocketAddress the remote {@link InetSocketAddress} from client * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. */ ChannelFuture allowed(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress); /** * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept(). * This method enables your implementation to send a message back to the client before closing * or whatever you need. This method returns a ChannelFuture on which the implementation * will wait uninterruptibly before closing the channel.
* For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. * * @param inetSocketAddress the remote {@link InetSocketAddress} from client * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. */ ChannelFuture refused(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress); /** * Called in handleUpstream, if this channel was previously blocked, * to check if whatever the event, it should be passed to the next entry in the pipeline.
* If one wants to not block events, just overridden this method by returning always true.

* Note that OPENED and BOUND events are still passed to the next entry in the pipeline since * those events come out before the CONNECTED event and so the possibility to filter the connection. * * @return True if the event should continue, False if the event should not continue * since this channel was blocked by this filter */ boolean continues(ChannelHandlerContext ctx, ChannelEvent e); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRule.java000066400000000000000000000016471225554127700312530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; /** This Interface defines an Ip Filter Rule. */ public interface IpFilterRule extends IpSet { /** @return True if this Rule is an ALLOW rule */ boolean isAllowRule(); /** @return True if this Rule is a DENY rule */ boolean isDenyRule(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRuleHandler.java000066400000000000000000000226671225554127700325560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * Implementation of Filter of IP based on ALLOW and DENY rules.
*

* This implementation could be changed by implementing a new {@link IpFilterRule} than default * {@link IpV4SubnetFilterRule} (IPV4 support only), {@link IpSubnetFilterRule} (IPV4 and IPV6 support) * or {@link IpFilterRule} (IP and host name string pattern support) .
*
* The check is done by going from step to step in the underlying array of IpFilterRule.
* Each {@link IpFilterRule} answers to the method accept if the {@link InetAddress} is accepted or not, * according to its implementation. If an InetAddress arrives at the end of the list, as in Firewall * usual rules, the InetAddress is therefore accepted by default.
*
    *
  • If it was constructed with True as first argument, * the IpFilterRule is an ALLOW rule (every InetAddress that fits in the rule will be accepted).
  • *
  • If it was constructed with False as first argument, * the IpFilterRule is a DENY rule (every InetAddress that fits in the rule will be refused).
  • *

*
* An empty list means allow all (no limitation).

* For efficiency reason, you should not add/remove too frequently IpFilterRules to/from this handler. * You should prefer to replace an entry (set method) with an ALLOW/DENY ALL IpFilterRule * if possible.


* This handler should be created only once and reused on every pipeline since it handles * a global status of what is allowed or blocked.

*

* Note that {@link IpSubnetFilterRule} which supports IPV4 and IPV6 should be used with as much as * possible no mixed IP protocol. Both IPV4 and IPV6 are supported but a mix (IpFilter in IPV6 notation * and the address from the channel in IPV4, or the reverse) can lead to wrong result. */ @Sharable public class IpFilterRuleHandler extends IpFilteringHandlerImpl { /** List of {@link IpFilterRule} */ private final CopyOnWriteArrayList ipFilterRuleList = new CopyOnWriteArrayList(); /** Constructor from a new list of IpFilterRule */ public IpFilterRuleHandler(List newList) { if (newList != null) { ipFilterRuleList.addAll(newList); } } /** * Empty constructor (no IpFilterRule in the List at construction). In such a situation, * empty list implies allow all. */ public IpFilterRuleHandler() { } // Below are methods directly inspired from CopyOnWriteArrayList methods /** Add an ipFilterRule in the list at the end */ public void add(IpFilterRule ipFilterRule) { if (ipFilterRule == null) { throw new NullPointerException("IpFilterRule can not be null"); } ipFilterRuleList.add(ipFilterRule); } /** Add an ipFilterRule in the list at the specified position (shifting to the right other elements) */ public void add(int index, IpFilterRule ipFilterRule) { if (ipFilterRule == null) { throw new NullPointerException("IpFilterRule can not be null"); } ipFilterRuleList.add(index, ipFilterRule); } /** * Appends all of the elements in the specified collection to the end of this list, * in the order that they are returned by the specified collection's iterator. */ public void addAll(Collection c) { if (c == null) { throw new NullPointerException("Collection can not be null"); } ipFilterRuleList.addAll(c); } /** Inserts all of the elements in the specified collection into this list, starting at the specified position. */ public void addAll(int index, Collection c) { if (c == null) { throw new NullPointerException("Collection can not be null"); } ipFilterRuleList.addAll(index, c); } /** * Append the element if not present. * * @return the number of elements added */ public int addAllAbsent(Collection c) { if (c == null) { throw new NullPointerException("Collection can not be null"); } return ipFilterRuleList.addAllAbsent(c); } /** * Append the element if not present. * * @return true if the element was added */ public boolean addIfAbsent(IpFilterRule ipFilterRule) { if (ipFilterRule == null) { throw new NullPointerException("IpFilterRule can not be null"); } return ipFilterRuleList.addIfAbsent(ipFilterRule); } /** Clear the list */ public void clear() { ipFilterRuleList.clear(); } /** * Returns true if this list contains the specified element * * @return true if this list contains the specified element */ public boolean contains(IpFilterRule ipFilterRule) { if (ipFilterRule == null) { throw new NullPointerException("IpFilterRule can not be null"); } return ipFilterRuleList.contains(ipFilterRule); } /** * Returns true if this list contains all of the elements of the specified collection * * @return true if this list contains all of the elements of the specified collection */ public boolean containsAll(Collection c) { if (c == null) { throw new NullPointerException("Collection can not be null"); } return ipFilterRuleList.containsAll(c); } /** * Returns the element at the specified position in this list * * @return the element at the specified position in this list */ public IpFilterRule get(int index) { return ipFilterRuleList.get(index); } /** * Returns true if this list contains no elements * * @return true if this list contains no elements */ public boolean isEmpty() { return ipFilterRuleList.isEmpty(); } /** Remove the ipFilterRule from the list */ public void remove(IpFilterRule ipFilterRule) { if (ipFilterRule == null) { throw new NullPointerException("IpFilterRule can not be null"); } ipFilterRuleList.remove(ipFilterRule); } /** * Removes the element at the specified position in this list * * @return the element previously at the specified position */ public IpFilterRule remove(int index) { return ipFilterRuleList.remove(index); } /** Removes from this list all of its elements that are contained in the specified collection */ public void removeAll(Collection c) { if (c == null) { throw new NullPointerException("Collection can not be null"); } ipFilterRuleList.removeAll(c); } /** Retains only the elements in this list that are contained in the specified collection */ public void retainAll(Collection c) { if (c == null) { throw new NullPointerException("Collection can not be null"); } ipFilterRuleList.retainAll(c); } /** * Replaces the element at the specified position in this list with the specified element * * @return the element previously at the specified position */ public IpFilterRule set(int index, IpFilterRule ipFilterRule) { if (ipFilterRule == null) { throw new NullPointerException("IpFilterRule can not be null"); } return ipFilterRuleList.set(index, ipFilterRule); } /** * Returns the number of elements in this list. * * @return the number of elements in this list. */ public int size() { return ipFilterRuleList.size(); } @Override protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) throws Exception { if (ipFilterRuleList.isEmpty()) { // No limitation neither in deny or allow, so accept return true; } InetAddress inetAddress = inetSocketAddress.getAddress(); Iterator iterator = ipFilterRuleList.iterator(); IpFilterRule ipFilterRule; while (iterator.hasNext()) { ipFilterRule = iterator.next(); if (ipFilterRule.contains(inetAddress)) { // Match founds, is it a ALLOW or DENY rule return ipFilterRule.isAllowRule(); } } // No limitation founds and no allow either, but as it is like Firewall rules, it is therefore accepted return true; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRuleList.java000066400000000000000000000061211225554127700320770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.StringUtil; import java.net.UnknownHostException; import java.util.ArrayList; /** * The Class IpFilterRuleList is a helper class to generate a List of Rules from a string. * In case of parse errors no exceptions are thrown. The error is logged. *
* Rule List Syntax: *
*

 * RuleList ::= Rule[,Rule]*
 * Rule ::= AllowRule | BlockRule
 * AllowRule ::= +Filter
 * BlockRule ::= -Filter
 * Filter ::= PatternFilter | CIDRFilter
 * PatternFilter ::= @see PatternRule
 * CIDRFilter ::= c:CIDRFilter
 * CIDRFilter ::= @see CIDR.newCIDR(String)
 * 
*
* Example: allow only localhost: *
* new IPFilterRuleHandler().addAll(new IpFilterRuleList("+n:localhost, -n:*")); *
*/ public class IpFilterRuleList extends ArrayList { private static final long serialVersionUID = -6164162941749588780L; private static final InternalLogger logger = InternalLoggerFactory.getInstance(IpFilterRuleList.class); /** * Instantiates a new ip filter rule list. * * @param rules the rules */ public IpFilterRuleList(String rules) { parseRules(rules); } private void parseRules(String rules) { String[] ruless = StringUtil.split(rules, ','); for (String rule : ruless) { parseRule(rule.trim()); } } private void parseRule(String rule) { if (rule == null || rule.length() == 0) { return; } if (!(rule.startsWith("+") || rule.startsWith("-"))) { if (logger.isErrorEnabled()) { logger.error("syntax error in ip filter rule:" + rule); } return; } boolean allow = rule.startsWith("+"); if (rule.charAt(1) == 'n' || rule.charAt(1) == 'i') { add(new PatternRule(allow, rule.substring(1))); } else if (rule.charAt(1) == 'c') { try { add(new IpSubnetFilterRule(allow, rule.substring(3))); } catch (UnknownHostException e) { if (logger.isErrorEnabled()) { logger.error("error parsing ip filter " + rule, e); } } } else { if (logger.isErrorEnabled()) { logger.error("syntax error in ip filter rule:" + rule); } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpFilteringHandler.java000066400000000000000000000021661225554127700324140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; /** * The Interface IpFilteringHandler. * A Filter of IP. *
* Users can add an {@link IpFilterListener} to add specific actions in case a connection is allowed or refused. */ public interface IpFilteringHandler { /** * Sets the filter listener. * * @param listener the new ip filter listener */ void setIpFilterListener(IpFilterListener listener); /** Remove the filter listener. */ void removeIpFilterListener(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpFilteringHandlerImpl.java000066400000000000000000000156451225554127700332440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.InetSocketAddress; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.Channels; // TODO: Auto-generated Javadoc /** General class that handle Ip Filtering. */ public abstract class IpFilteringHandlerImpl implements ChannelUpstreamHandler, IpFilteringHandler { private IpFilterListener listener; /** * Called when the channel is connected. It returns True if the corresponding connection * is to be allowed. Else it returns False. * * @param inetSocketAddress the remote {@link InetSocketAddress} from client * @return True if the corresponding connection is allowed, else False. */ protected abstract boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) throws Exception; /** * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept(). * This method enables your implementation to send a message back to the client before closing * or whatever you need. This method returns a ChannelFuture on which the implementation * will wait uninterruptibly before closing the channel.
* For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. * * @param inetSocketAddress the remote {@link InetSocketAddress} from client * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. */ protected ChannelFuture handleRefusedChannel(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) throws Exception { if (listener == null) { return null; } return listener.refused(ctx, e, inetSocketAddress); } protected ChannelFuture handleAllowedChannel(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) throws Exception { if (listener == null) { return null; } return listener.allowed(ctx, e, inetSocketAddress); } /** * Internal method to test if the current channel is blocked. Should not be overridden. * * @return True if the current channel is blocked, else False */ protected boolean isBlocked(ChannelHandlerContext ctx) { return ctx.getAttachment() != null; } /** * Called in handleUpstream, if this channel was previously blocked, * to check if whatever the event, it should be passed to the next entry in the pipeline.
* If one wants to not block events, just overridden this method by returning always true.

* Note that OPENED and BOUND events are still passed to the next entry in the pipeline since * those events come out before the CONNECTED event and so the possibility to filter the connection. * * @return True if the event should continue, False if the event should not continue * since this channel was blocked by this filter */ protected boolean continues(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (listener != null) { return listener.continues(ctx, e); } else { return false; } } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; switch (evt.getState()) { case OPEN: case BOUND: // Special case: OPEND and BOUND events are before CONNECTED, // but CLOSED and UNBOUND events are after DISCONNECTED: should those events be blocked too? if (isBlocked(ctx) && !continues(ctx, evt)) { // don't pass to next level since channel was blocked early return; } else { ctx.sendUpstream(e); return; } case CONNECTED: if (evt.getValue() != null) { // CONNECTED InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); if (!accept(ctx, e, inetSocketAddress)) { ctx.setAttachment(Boolean.TRUE); ChannelFuture future = handleRefusedChannel(ctx, e, inetSocketAddress); if (future != null) { future.addListener(ChannelFutureListener.CLOSE); } else { Channels.close(e.getChannel()); } if (isBlocked(ctx) && !continues(ctx, evt)) { // don't pass to next level since channel was blocked early return; } } else { handleAllowedChannel(ctx, e, inetSocketAddress); } // This channel is not blocked ctx.setAttachment(null); } else { // DISCONNECTED if (isBlocked(ctx) && !continues(ctx, evt)) { // don't pass to next level since channel was blocked early return; } } break; } } if (isBlocked(ctx) && !continues(ctx, e)) { // don't pass to next level since channel was blocked early return; } // Whatever it is, if not blocked, goes to the next level ctx.sendUpstream(e); } public void setIpFilterListener(IpFilterListener listener) { this.listener = listener; } public void removeIpFilterListener() { listener = null; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpSet.java000066400000000000000000000021121225554127700277150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.InetAddress; /** This Interface defines an IpSet object. */ public interface IpSet { /** * Compares the given InetAddress against the IpSet and returns true if * the InetAddress is contained in this Rule and false if not. * * @return returns true if the given IP address is contained in the current * IpSet. */ boolean contains(InetAddress inetAddress1); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpSubnet.java000066400000000000000000000125561225554127700304370ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.net.InetAddress; import java.net.UnknownHostException; /** * This class allows to check if an IP V4 or V6 Address is contained in a subnet.
*

* Supported IP V4 Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
*

Example1:
* IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
* System.out.println("Result: "+ ips.contains("192.168.1.123"));
* System.out.println("Result: "+ ips.contains(inetAddress2));
*
Example1 bis:
* IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
*

Example2:
* IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
* System.out.println("Result: "+ ips.contains("192.168.1.123"));
* System.out.println("Result: "+ ips.contains(inetAddress2));
*
Example2 bis:
* IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
*
* Supported IP V6 Formats for the Subnets are: a:b:c:d:e:f:g:h/NN (CIDR-Notation) * or any IPV6 notations (like a:b:c:d::/NN, a:b:c:d:e:f:w.x.y.z/NN) * and (InetAddress,Mask) where Mask is a integer for CIDR-notation * and (InetAddress,subnet).
*

Example1:
* IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");
* IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3::/24");
* System.out.println("Result: "+ ips.contains("1fff:0:0a88:85a3:0:0:ac1f:8001"));
* System.out.println("Result: "+ ips.contains(inetAddress2));
*
Example1 bis:
* IpSubnet ips = new IpSubnet(inetAddress, 24);
* where inetAddress2 is 1fff:0:0a88:85a3:0:0:ac1f:8001
*/ public class IpSubnet implements IpSet, Comparable { private static final InternalLogger logger = InternalLoggerFactory.getInstance(IpSubnet.class); /** Internal representation */ private final CIDR cidr; /** Create IpSubnet for ALL (used for ALLOW or DENY ALL) */ public IpSubnet() { // ALLOW or DENY ALL cidr = null; } /** * Create IpSubnet using the CIDR or normal Notation
* i.e.:
* IpSubnet subnet = new IpSubnet("10.10.10.0/24"); or
* IpSubnet subnet = new IpSubnet("10.10.10.0/255.255.255.0"); or
* IpSubnet subnet = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24"); * * @param netAddress a network address as string. */ public IpSubnet(String netAddress) throws UnknownHostException { cidr = CIDR.newCIDR(netAddress); } /** Create IpSubnet using the CIDR Notation */ public IpSubnet(InetAddress inetAddress, int cidrNetMask) throws UnknownHostException { cidr = CIDR.newCIDR(inetAddress, cidrNetMask); } /** Create IpSubnet using the normal Notation */ public IpSubnet(InetAddress inetAddress, String netMask) throws UnknownHostException { cidr = CIDR.newCIDR(inetAddress, netMask); } /** * Compares the given IP-Address against the Subnet and returns true if * the ip is in the subnet-ip-range and false if not. * * @param ipAddr an ipaddress * @return returns true if the given IP address is inside the currently * set network. */ public boolean contains(String ipAddr) throws UnknownHostException { InetAddress inetAddress1 = InetAddress.getByName(ipAddr); return contains(inetAddress1); } /** * Compares the given InetAddress against the Subnet and returns true if * the ip is in the subnet-ip-range and false if not. * * @return returns true if the given IP address is inside the currently * set network. */ public boolean contains(InetAddress inetAddress) { if (cidr == null) { // ANY return true; } return cidr.contains(inetAddress); } @Override public String toString() { return cidr.toString(); } @Override public boolean equals(Object o) { if (!(o instanceof IpSubnet)) { return false; } IpSubnet ipSubnet = (IpSubnet) o; return ipSubnet.cidr.equals(cidr); } @Override public int hashCode() { return cidr.hashCode(); } /** Compare two IpSubnet */ public int compareTo(IpSubnet o) { return cidr.toString().compareTo(o.cidr.toString()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpSubnetFilterRule.java000066400000000000000000000041771225554127700324350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.InetAddress; import java.net.UnknownHostException; /** * Ip V4 and Ip V6 filter rule.
*
* Note that mix of IPV4 and IPV6 is allowed but it is not recommended. So it is preferable to not * mix IPV4 addresses with IPV6 rules, even if it should work. */ public class IpSubnetFilterRule extends IpSubnet implements IpFilterRule { /** Is this IpV4Subnet an ALLOW or DENY rule */ private boolean isAllowRule = true; /** * Constructor for a ALLOW or DENY ALL * * @param allow True for ALLOW, False for DENY */ public IpSubnetFilterRule(boolean allow) { isAllowRule = allow; } /** @param allow True for ALLOW, False for DENY */ public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) throws UnknownHostException { super(inetAddress, cidrNetMask); isAllowRule = allow; } /** @param allow True for ALLOW, False for DENY */ public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) throws UnknownHostException { super(inetAddress, netMask); isAllowRule = allow; } /** @param allow True for ALLOW, False for DENY */ public IpSubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException { super(netAddress); isAllowRule = allow; } public boolean isAllowRule() { return isAllowRule; } public boolean isDenyRule() { return !isAllowRule; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpV4Subnet.java000066400000000000000000000201171225554127700306410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.StringUtil; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.StringTokenizer; /** * This class allows to check if an IP-V4-Address is contained in a subnet.
* Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
*

Example1:
* IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
* System.out.println("Result: "+ ips.contains("192.168.1.123"));
* System.out.println("Result: "+ ips.contains(inetAddress2));
*
Example1 bis:
* IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
*

Example2:
* IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
* System.out.println("Result: "+ ips.contains("192.168.1.123"));
* System.out.println("Result: "+ ips.contains(inetAddress2));
*
Example2 bis:
* IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
*/ public class IpV4Subnet implements IpSet, Comparable { private static final InternalLogger logger = InternalLoggerFactory.getInstance(IpV4Subnet.class); private static final int SUBNET_MASK = 0x80000000; private static final int BYTE_ADDRESS_MASK = 0xFF; private InetAddress inetAddress; private int subnet; private int mask; private int cidrMask; /** Create IpV4Subnet for ALL (used for ALLOW or DENY ALL) */ public IpV4Subnet() { // ALLOW or DENY ALL mask = -1; // other will be ignored inetAddress = null; subnet = 0; cidrMask = 0; } /** * Create IpV4Subnet using the CIDR or normal Notation
* i.e.: * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0"); * * @param netAddress a network address as string. */ public IpV4Subnet(String netAddress) throws UnknownHostException { setNetAddress(netAddress); } /** Create IpV4Subnet using the CIDR Notation */ public IpV4Subnet(InetAddress inetAddress, int cidrNetMask) { setNetAddress(inetAddress, cidrNetMask); } /** Create IpV4Subnet using the normal Notation */ public IpV4Subnet(InetAddress inetAddress, String netMask) { setNetAddress(inetAddress, netMask); } /** * Sets the Network Address in either CIDR or Decimal Notation.
* i.e.: setNetAddress("1.1.1.1/24"); or
* setNetAddress("1.1.1.1/255.255.255.0");
* * @param netAddress a network address as string. */ private void setNetAddress(String netAddress) throws UnknownHostException { String[] tokens = StringUtil.split(netAddress, '/'); if (tokens.length != 2) { throw new IllegalArgumentException("netAddress: " + netAddress + " (expected: CIDR or Decimal Notation)"); } if (tokens[1].length() < 3) { setNetId(tokens[0]); setCidrNetMask(Integer.parseInt(tokens[1])); } else { setNetId(tokens[0]); setNetMask(tokens[1]); } } /** Sets the Network Address in CIDR Notation. */ private void setNetAddress(InetAddress inetAddress, int cidrNetMask) { setNetId(inetAddress); setCidrNetMask(cidrNetMask); } /** Sets the Network Address in Decimal Notation. */ private void setNetAddress(InetAddress inetAddress, String netMask) { setNetId(inetAddress); setNetMask(netMask); } /** * Sets the BaseAdress of the Subnet.
* i.e.: setNetId("192.168.1.0"); * * @param netId a network ID */ private void setNetId(String netId) throws UnknownHostException { InetAddress inetAddress1 = InetAddress.getByName(netId); setNetId(inetAddress1); } /** * Compute integer representation of InetAddress * * @return the integer representation */ private static int toInt(InetAddress inetAddress1) { byte[] address = inetAddress1.getAddress(); int net = 0; for (byte addres : address) { net <<= 8; net |= addres & BYTE_ADDRESS_MASK; } return net; } /** Sets the BaseAdress of the Subnet. */ private void setNetId(InetAddress inetAddress) { this.inetAddress = inetAddress; subnet = toInt(inetAddress); } /** * Sets the Subnet's Netmask in Decimal format.
* i.e.: setNetMask("255.255.255.0"); * * @param netMask a network mask */ private void setNetMask(String netMask) { StringTokenizer nm = new StringTokenizer(netMask, "."); int i = 0; int[] netmask = new int[4]; while (nm.hasMoreTokens()) { netmask[i] = Integer.parseInt(nm.nextToken()); i++; } int mask1 = 0; for (i = 0; i < 4; i++) { mask1 += Integer.bitCount(netmask[i]); } setCidrNetMask(mask1); } /** * Sets the CIDR Netmask
* i.e.: setCidrNetMask(24); * * @param cidrNetMask a netmask in CIDR notation */ private void setCidrNetMask(int cidrNetMask) { cidrMask = cidrNetMask; mask = SUBNET_MASK >> cidrMask - 1; } /** * Compares the given IP-Address against the Subnet and returns true if * the ip is in the subnet-ip-range and false if not. * * @param ipAddr an ipaddress * @return returns true if the given IP address is inside the currently * set network. */ public boolean contains(String ipAddr) throws UnknownHostException { InetAddress inetAddress1 = InetAddress.getByName(ipAddr); return contains(inetAddress1); } /** * Compares the given InetAddress against the Subnet and returns true if * the ip is in the subnet-ip-range and false if not. * * @return returns true if the given IP address is inside the currently * set network. */ public boolean contains(InetAddress inetAddress1) { if (mask == -1) { // ANY return true; } return (toInt(inetAddress1) & mask) == subnet; } @Override public String toString() { return inetAddress.getHostAddress() + '/' + cidrMask; } @Override public boolean equals(Object o) { if (!(o instanceof IpV4Subnet)) { return false; } IpV4Subnet ipV4Subnet = (IpV4Subnet) o; return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask; } @Override public int hashCode() { return subnet; } /** Compare two IpV4Subnet */ public int compareTo(IpV4Subnet o) { if (o.subnet == subnet && o.cidrMask == cidrMask) { return 0; } if (o.subnet < subnet) { return 1; } if (o.subnet > subnet) { return -1; } if (o.cidrMask < cidrMask) { // greater Mask means less IpAddresses so -1 return -1; } return 1; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/IpV4SubnetFilterRule.java000066400000000000000000000036321225554127700326420ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.InetAddress; import java.net.UnknownHostException; /** IpV4 only Filter Rule */ public class IpV4SubnetFilterRule extends IpV4Subnet implements IpFilterRule { /** Is this IpV4Subnet an ALLOW or DENY rule */ private boolean isAllowRule = true; /** * Constructor for a ALLOW or DENY ALL * * @param allow True for ALLOW, False for DENY */ public IpV4SubnetFilterRule(boolean allow) { isAllowRule = allow; } /** @param allow True for ALLOW, False for DENY */ public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) { super(inetAddress, cidrNetMask); isAllowRule = allow; } /** @param allow True for ALLOW, False for DENY */ public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) { super(inetAddress, netMask); isAllowRule = allow; } /** @param allow True for ALLOW, False for DENY */ public IpV4SubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException { super(netAddress); isAllowRule = allow; } public boolean isAllowRule() { return isAllowRule; } public boolean isDenyRule() { return !isAllowRule; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/OneIpFilterHandler.java000066400000000000000000000056701225554127700323630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; /** * Handler that block any new connection if there are already a currently active * channel connected with the same InetAddress (IP).
*
*

* Take care to not change isBlocked method except if you know what you are doing * since it is used to test if the current closed connection is to be removed * or not from the map of currently connected channel. */ @Sharable public class OneIpFilterHandler extends IpFilteringHandlerImpl { /** HashMap of current remote connected InetAddress */ private final ConcurrentMap connectedSet = new ConcurrentHashMap(); @Override protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) throws Exception { InetAddress inetAddress = inetSocketAddress.getAddress(); if (connectedSet.containsKey(inetAddress)) { return false; } connectedSet.put(inetAddress, Boolean.TRUE); return true; } @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { super.handleUpstream(ctx, e); // Try to remove entry from Map if already exists if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; if (evt.getState() == ChannelState.CONNECTED) { if (evt.getValue() == null) { // DISCONNECTED but was this channel blocked or not if (isBlocked(ctx)) { // remove inetsocketaddress from set since this channel was not blocked before InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); connectedSet.remove(inetSocketAddress.getAddress()); } } } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/PatternRule.java000066400000000000000000000125741225554127700311530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.StringUtil; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.regex.Pattern; /** * The Class PatternRule represents an IP filter rule using string patterns. *
* Rule Syntax: *
*

 * Rule ::= [n|i]:address          n stands for computer name, i for ip address
 * address ::= <regex> | localhost
 * regex is a regular expression with '*' as multi character and '?' as single character wild card
 * 
*
* Example: allow localhost: *
* new PatternRule(true, "n:localhost") *
* Example: allow local lan: *
* new PatternRule(true, "i:192.168.0.*") *
* Example: block all *
* new PatternRule(false, "n:*") *
*/ public class PatternRule implements IpFilterRule, Comparable { private static final InternalLogger logger = InternalLoggerFactory.getInstance(PatternRule.class); private Pattern ipPattern; private Pattern namePattern; private boolean isAllowRule = true; private boolean localhost; private final String pattern; /** * Instantiates a new pattern rule. * * @param allow indicates if this is an allow or block rule * @param pattern the filter pattern */ public PatternRule(boolean allow, String pattern) { isAllowRule = allow; this.pattern = pattern; parse(pattern); } /** * returns the pattern. * * @return the pattern */ public String getPattern() { return pattern; } public boolean isAllowRule() { return isAllowRule; } public boolean isDenyRule() { return !isAllowRule; } public boolean contains(InetAddress inetAddress) { if (localhost) { if (isLocalhost(inetAddress)) { return true; } } if (ipPattern != null) { if (ipPattern.matcher(inetAddress.getHostAddress()).matches()) { return true; } } if (namePattern != null) { if (namePattern.matcher(inetAddress.getHostName()).matches()) { return true; } } return false; } private void parse(String pattern) { if (pattern == null) { return; } String[] acls = StringUtil.split(pattern, ','); String ip = ""; String name = ""; for (String c : acls) { c = c.trim(); if ("n:localhost".equals(c)) { localhost = true; } else if (c.startsWith("n:")) { name = addRule(name, c.substring(2)); } else if (c.startsWith("i:")) { ip = addRule(ip, c.substring(2)); } } if (ip.length() != 0) { ipPattern = Pattern.compile(ip); } if (name.length() != 0) { namePattern = Pattern.compile(name); } } private static String addRule(String pattern, String rule) { if (rule == null || rule.length() == 0) { return pattern; } if (pattern.length() != 0) { pattern += "|"; } rule = rule.replaceAll("\\.", "\\\\."); rule = rule.replaceAll("\\*", ".*"); rule = rule.replaceAll("\\?", "."); pattern += '(' + rule + ')'; return pattern; } private static boolean isLocalhost(InetAddress address) { try { if (address.equals(InetAddress.getLocalHost())) { return true; } } catch (UnknownHostException e) { if (logger.isInfoEnabled()) { logger.info("error getting ip of localhost", e); } } try { InetAddress[] addrs = InetAddress.getAllByName("127.0.0.1"); for (InetAddress addr : addrs) { if (addr.equals(address)) { return true; } } } catch (UnknownHostException e) { if (logger.isInfoEnabled()) { logger.info("error getting ip of localhost", e); } } return false; } public int compareTo(Object o) { if (o == null) { return -1; } if (!(o instanceof PatternRule)) { return -1; } PatternRule p = (PatternRule) o; if (p.isAllowRule() && !isAllowRule) { return -1; } if (pattern == null && p.pattern == null) { return 0; } if (pattern != null) { return pattern.compareTo(p.getPattern()); } return -1; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ipfilter/package-info.java000066400000000000000000000116631225554127700312300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Implementation of a Ip based Filter handlers.
*

*

The main goal of this package is to allow to filter connections based on IP rules. * The main interface is {@link org.jboss.netty.handler.ipfilter.IpFilteringHandler} which * all filters will extend.

* *

Two IP filtering are proposed:
*

    *
  • {@link org.jboss.netty.handler.ipfilter.OneIpFilterHandler}: This filter proposes to allow * only one connection by client's IP Address. I.E. this filter will prevent two connections * from the same client based on its IP address.


  • * *
  • {@link org.jboss.netty.handler.ipfilter.IpFilterRuleHandler}: This filter proposes to allow * or block IP range (based on standard notation or on CIDR notation) when the connection is * running. It relies on another class like IpV4SubnetFilterRule (IPV4 support only), * IpSubnetFilterRule (IPV4 and IPV6 support) or PatternRule (string pattern * support) which implements those Ip ranges.


  • * *

* *

Standard use could be as follow: The accept method must be overridden (of course you can * override others).

* *

    *
  • accept method allows to specify your way of choosing if a new connection is * to be allowed or not.

  • * In OneIpFilterHandler and IpFilterRuleHandler, * this method is already implemented.
    *
    * *
  • handleRefusedChannel method is executed when the accept method filters (blocks, so returning * false) the new connection. This method allows you to implement specific actions to be taken * before the channel is closed. After this method is called, the channel is immediately closed.

  • * * So if you want to send back a message to the client, don't forget to return a respectful * ChannelFuture, otherwise the message could be missed since the channel will be closed immediately * after this call and the waiting on this channelFuture (at least with respect of asynchronous * operations).

    * Per default implementation this method invokes an {@link org.jboss.netty.handler.ipfilter.IpFilterListener} * or returns null if no listener has been set. *

    * *
  • continues is called when any event appears after CONNECTED event and only for * blocked channels.

  • * It should return True if this new event has to go to next handlers * in the pipeline if any, and False (default) if no events has to be passed to the next * handlers when a channel is blocked. This is intend to prevent any unnecessary action since the * connection is refused.
    * However, you could change its behavior for instance because you don't want that any event * will be blocked by this filter by returning always true or according to some events.
    * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since * those events come out before the CONNECTED event, so there is no possibility to filter those two events * before the CONNECTED event shows up. Therefore, you might want to let CLOSED and UNBOUND be passed * to the next entry in the pipeline.

    * Per default implementation this method invokes an {@link org.jboss.netty.handler.ipfilter.IpFilterListener} * or returns false if no listener has been set. *

    * *
  • Finally handleUpstream traps the CONNECTED and DISCONNECTED events.

  • * If in the CONNECTED events the channel is blocked (accept refused the channel), * then any new events on this channel will be blocked.
    * However, you could change its behavior for instance because you don't want that all events * will be blocked by this filter by testing the result of isBlocked, and if so, * calling ctx.sendUpstream(e); after calling the super method or by changing the * continues method.

    *



* * A typical setup for ip filter for TCP/IP socket would be: * *
 * {@link org.jboss.netty.channel.ChannelPipeline} pipeline = ...;
 *
 * IpFilterRuleHandler firewall = new IpFilterRuleHandler();
 * firewall.addAll(new IpFilterRuleList("+n:localhost, +c:192.168.0.0/27, -n:*"));
 * pipeline.addFirst("firewall", firewall);
 * 
* * @apiviz.exclude ^java\.lang\. */ package org.jboss.netty.handler.ipfilter; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/logging/000077500000000000000000000000001225554127700256425ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/logging/LoggingHandler.java000066400000000000000000000262571225554127700314050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.logging; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.logging.InternalLogLevel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * A {@link ChannelHandler} that logs all events via {@link InternalLogger}. * By default, all events are logged at DEBUG level. You can extend * this class and override {@link #log(ChannelEvent)} to change the default * behavior. * @apiviz.landmark */ @Sharable public class LoggingHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler { private static final InternalLogLevel DEFAULT_LEVEL = InternalLogLevel.DEBUG; private static final String NEWLINE = String.format("%n"); private static final String[] BYTE2HEX = new String[256]; private static final String[] HEXPADDING = new String[16]; private static final String[] BYTEPADDING = new String[16]; private static final char[] BYTE2CHAR = new char[256]; static { int i; // Generate the lookup table for byte-to-hex-dump conversion for (i = 0; i < 10; i ++) { StringBuilder buf = new StringBuilder(3); buf.append(" 0"); buf.append(i); BYTE2HEX[i] = buf.toString(); } for (; i < 16; i ++) { StringBuilder buf = new StringBuilder(3); buf.append(" 0"); buf.append((char) ('a' + i - 10)); BYTE2HEX[i] = buf.toString(); } for (; i < BYTE2HEX.length; i ++) { StringBuilder buf = new StringBuilder(3); buf.append(' '); buf.append(Integer.toHexString(i)); BYTE2HEX[i] = buf.toString(); } // Generate the lookup table for hex dump paddings for (i = 0; i < HEXPADDING.length; i ++) { int padding = HEXPADDING.length - i; StringBuilder buf = new StringBuilder(padding * 3); for (int j = 0; j < padding; j ++) { buf.append(" "); } HEXPADDING[i] = buf.toString(); } // Generate the lookup table for byte dump paddings for (i = 0; i < BYTEPADDING.length; i ++) { int padding = BYTEPADDING.length - i; StringBuilder buf = new StringBuilder(padding); for (int j = 0; j < padding; j ++) { buf.append(' '); } BYTEPADDING[i] = buf.toString(); } // Generate the lookup table for byte-to-char conversion for (i = 0; i < BYTE2CHAR.length; i ++) { if (i <= 0x1f || i >= 0x7f) { BYTE2CHAR[i] = '.'; } else { BYTE2CHAR[i] = (char) i; } } } private final InternalLogger logger; private final InternalLogLevel level; private final boolean hexDump; /** * Creates a new instance whose logger name is the fully qualified class * name of the instance with hex dump enabled. */ public LoggingHandler() { this(true); } /** * Creates a new instance whose logger name is the fully qualified class * name of the instance. * * @param level the log level */ public LoggingHandler(InternalLogLevel level) { this(level, true); } /** * Creates a new instance whose logger name is the fully qualified class * name of the instance. * * @param hexDump {@code true} if and only if the hex dump of the received * message is logged */ public LoggingHandler(boolean hexDump) { this(DEFAULT_LEVEL, hexDump); } /** * Creates a new instance whose logger name is the fully qualified class * name of the instance. * * @param level the log level * @param hexDump {@code true} if and only if the hex dump of the received * message is logged */ public LoggingHandler(InternalLogLevel level, boolean hexDump) { if (level == null) { throw new NullPointerException("level"); } logger = InternalLoggerFactory.getInstance(getClass()); this.level = level; this.hexDump = hexDump; } /** * Creates a new instance with the specified logger name and with hex dump * enabled. */ public LoggingHandler(Class clazz) { this(clazz, true); } /** * Creates a new instance with the specified logger name. * * @param hexDump {@code true} if and only if the hex dump of the received * message is logged */ public LoggingHandler(Class clazz, boolean hexDump) { this(clazz, DEFAULT_LEVEL, hexDump); } /** * Creates a new instance with the specified logger name. * * @param level the log level */ public LoggingHandler(Class clazz, InternalLogLevel level) { this(clazz, level, true); } /** * Creates a new instance with the specified logger name. * * @param level the log level * @param hexDump {@code true} if and only if the hex dump of the received * message is logged */ public LoggingHandler(Class clazz, InternalLogLevel level, boolean hexDump) { if (clazz == null) { throw new NullPointerException("clazz"); } if (level == null) { throw new NullPointerException("level"); } logger = InternalLoggerFactory.getInstance(clazz); this.level = level; this.hexDump = hexDump; } /** * Creates a new instance with the specified logger name and with hex dump * enabled. */ public LoggingHandler(String name) { this(name, true); } /** * Creates a new instance with the specified logger name. * * @param hexDump {@code true} if and only if the hex dump of the received * message is logged */ public LoggingHandler(String name, boolean hexDump) { this(name, DEFAULT_LEVEL, hexDump); } /** * Creates a new instance with the specified logger name. * * @param level the log level * @param hexDump {@code true} if and only if the hex dump of the received * message is logged */ public LoggingHandler(String name, InternalLogLevel level, boolean hexDump) { if (name == null) { throw new NullPointerException("name"); } if (level == null) { throw new NullPointerException("level"); } logger = InternalLoggerFactory.getInstance(name); this.level = level; this.hexDump = hexDump; } /** * Returns the {@link InternalLogger} that this handler uses to log * a {@link ChannelEvent}. */ public InternalLogger getLogger() { return logger; } /** * Returns the {@link InternalLogLevel} that this handler uses to log * a {@link ChannelEvent}. */ public InternalLogLevel getLevel() { return level; } /** * Logs the specified event to the {@link InternalLogger} returned by * {@link #getLogger()}. If hex dump has been enabled for this handler, * the hex dump of the {@link ChannelBuffer} in a {@link MessageEvent} will * be logged together. */ public void log(ChannelEvent e) { if (getLogger().isEnabled(level)) { String msg = e.toString(); // Append hex dump if necessary. if (hexDump && e instanceof MessageEvent) { MessageEvent me = (MessageEvent) e; if (me.getMessage() instanceof ChannelBuffer) { msg += formatBuffer((ChannelBuffer) me.getMessage()); } } // Log the message (and exception if available.) if (e instanceof ExceptionEvent) { getLogger().log(level, msg, ((ExceptionEvent) e).getCause()); } else { getLogger().log(level, msg); } } } private static String formatBuffer(ChannelBuffer buf) { int length = buf.readableBytes(); int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4; StringBuilder dump = new StringBuilder(rows * 80); dump.append( NEWLINE + " +-------------------------------------------------+" + NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" + NEWLINE + "+--------+-------------------------------------------------+----------------+"); final int startIndex = buf.readerIndex(); final int endIndex = buf.writerIndex(); int i; for (i = startIndex; i < endIndex; i ++) { int relIdx = i - startIndex; int relIdxMod16 = relIdx & 15; if (relIdxMod16 == 0) { dump.append(NEWLINE); dump.append(Long.toHexString(relIdx & 0xFFFFFFFFL | 0x100000000L)); dump.setCharAt(dump.length() - 9, '|'); dump.append('|'); } dump.append(BYTE2HEX[buf.getUnsignedByte(i)]); if (relIdxMod16 == 15) { dump.append(" |"); for (int j = i - 15; j <= i; j ++) { dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]); } dump.append('|'); } } if ((i - startIndex & 15) != 0) { int remainder = length & 15; dump.append(HEXPADDING[remainder]); dump.append(" |"); for (int j = i - remainder; j < i; j ++) { dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]); } dump.append(BYTEPADDING[remainder]); dump.append('|'); } dump.append( NEWLINE + "+--------+-------------------------------------------------+----------------+"); return dump.toString(); } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { log(e); ctx.sendUpstream(e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { log(e); ctx.sendDownstream(e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/logging/package-info.java000066400000000000000000000015521225554127700310340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Logs a {@link org.jboss.netty.channel.ChannelEvent} for debugging purpose * using an {@link org.jboss.netty.logging.InternalLogger}. * * @apiviz.hidden * @apiviz.exclude \.channel\. */ package org.jboss.netty.handler.logging; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/queue/000077500000000000000000000000001225554127700253405ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/queue/BlockingReadHandler.java000066400000000000000000000222761225554127700320360ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.queue; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.internal.DeadLockProofWorker; import java.io.IOException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; /** * Emulates blocking read operation. This handler stores all received messages * into a {@link BlockingQueue} and returns the received messages when * {@link #read()}, {@link #read(long, TimeUnit)}, {@link #readEvent()}, or * {@link #readEvent(long, TimeUnit)} method is called. *

* Please note that this handler is only useful for the cases where there are * very small number of connections, such as testing and simple client-side * application development. *

* Also, any handler placed after this handler will never receive * {@code messageReceived}, {@code exceptionCaught}, and {@code channelClosed} * events, hence it should be placed in the last place in a pipeline. *

* Here is an example that demonstrates the usage: *

 * {@link BlockingReadHandler}<{@link ChannelBuffer}> reader =
 *         new {@link BlockingReadHandler}<{@link ChannelBuffer}>();
 * {@link ChannelPipeline} p = ...;
 * p.addLast("reader", reader);
 *
 * ...
 *
 * // Read a message from a channel in a blocking manner.
 * try {
 *     {@link ChannelBuffer} buf = reader.read(60, TimeUnit.SECONDS);
 *     if (buf == null) {
 *         // Connection closed.
 *     } else {
 *         // Handle the received message here.
 *     }
 * } catch ({@link BlockingReadTimeoutException} e) {
 *     // Read timed out.
 * } catch (IOException e) {
 *     // Other read errors
 * }
 * 
* * @param the type of the received messages */ public class BlockingReadHandler extends SimpleChannelUpstreamHandler { private final BlockingQueue queue; private volatile boolean closed; /** * Creates a new instance with {@link LinkedBlockingQueue} */ public BlockingReadHandler() { this(new LinkedBlockingQueue()); } /** * Creates a new instance with the specified {@link BlockingQueue}. */ public BlockingReadHandler(BlockingQueue queue) { if (queue == null) { throw new NullPointerException("queue"); } this.queue = queue; } /** * Returns the queue which stores the received messages. The default * implementation returns the queue which was specified in the constructor. */ protected BlockingQueue getQueue() { return queue; } /** * Returns {@code true} if and only if the {@link Channel} associated with * this handler has been closed. * * @throws IllegalStateException * if this handler was not added to a {@link ChannelPipeline} yet */ public boolean isClosed() { return closed; } /** * Waits until a new message is received or the associated {@link Channel} * is closed. * * @return the received message or {@code null} if the associated * {@link Channel} has been closed * @throws IOException * if failed to receive a new message * @throws InterruptedException * if the operation has been interrupted */ public E read() throws IOException, InterruptedException { ChannelEvent e = readEvent(); if (e == null) { return null; } if (e instanceof MessageEvent) { return getMessage((MessageEvent) e); } else if (e instanceof ExceptionEvent) { throw (IOException) new IOException().initCause(((ExceptionEvent) e).getCause()); } else { throw new IllegalStateException(); } } /** * Waits until a new message is received or the associated {@link Channel} * is closed. * * @param timeout * the amount time to wait until a new message is received. * If no message is received within the timeout, * {@link BlockingReadTimeoutException} is thrown. * @param unit * the unit of {@code timeout} * * @return the received message or {@code null} if the associated * {@link Channel} has been closed * @throws BlockingReadTimeoutException * if no message was received within the specified timeout * @throws IOException * if failed to receive a new message * @throws InterruptedException * if the operation has been interrupted */ public E read(long timeout, TimeUnit unit) throws IOException, InterruptedException { ChannelEvent e = readEvent(timeout, unit); if (e == null) { return null; } if (e instanceof MessageEvent) { return getMessage((MessageEvent) e); } else if (e instanceof ExceptionEvent) { throw (IOException) new IOException().initCause(((ExceptionEvent) e).getCause()); } else { throw new IllegalStateException(); } } /** * Waits until a new {@link ChannelEvent} is received or the associated * {@link Channel} is closed. * * @return a {@link MessageEvent} or an {@link ExceptionEvent}. * {@code null} if the associated {@link Channel} has been closed * @throws InterruptedException * if the operation has been interrupted */ public ChannelEvent readEvent() throws InterruptedException { detectDeadLock(); if (isClosed()) { if (getQueue().isEmpty()) { return null; } } ChannelEvent e = getQueue().take(); if (e instanceof ChannelStateEvent) { // channelClosed has been triggered. assert closed; return null; } else { return e; } } /** * Waits until a new {@link ChannelEvent} is received or the associated * {@link Channel} is closed. * * @param timeout * the amount time to wait until a new {@link ChannelEvent} is * received. If no message is received within the timeout, * {@link BlockingReadTimeoutException} is thrown. * @param unit * the unit of {@code timeout} * * @return a {@link MessageEvent} or an {@link ExceptionEvent}. * {@code null} if the associated {@link Channel} has been closed * @throws BlockingReadTimeoutException * if no event was received within the specified timeout * @throws InterruptedException * if the operation has been interrupted */ public ChannelEvent readEvent( long timeout, TimeUnit unit) throws InterruptedException, BlockingReadTimeoutException { detectDeadLock(); if (isClosed()) { if (getQueue().isEmpty()) { return null; } } ChannelEvent e = getQueue().poll(timeout, unit); if (e == null) { throw new BlockingReadTimeoutException(); } else if (e instanceof ChannelStateEvent) { // channelClosed has been triggered. assert closed; return null; } else { return e; } } private static void detectDeadLock() { if (DeadLockProofWorker.PARENT.get() != null) { throw new IllegalStateException( "read*(...) in I/O thread causes a dead lock or " + "sudden performance drop. Implement a state machine or " + "call read*() from a different thread."); } } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { getQueue().put(e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { getQueue().put(e); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { closed = true; getQueue().put(e); } @SuppressWarnings("unchecked") private E getMessage(MessageEvent e) { return (E) e.getMessage(); } } BlockingReadTimeoutException.java000066400000000000000000000030441225554127700336770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/queue/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.queue; import java.io.IOException; import java.io.InterruptedIOException; /** * A {@link IOException} raised by {@link BlockingReadHandler} when no data * was read within a certain period of time. */ public class BlockingReadTimeoutException extends InterruptedIOException { private static final long serialVersionUID = 356009226872649493L; /** * Creates a new instance. */ public BlockingReadTimeoutException() { } /** * Creates a new instance. */ public BlockingReadTimeoutException(String message, Throwable cause) { super(message); initCause(cause); } /** * Creates a new instance. */ public BlockingReadTimeoutException(String message) { super(message); } /** * Creates a new instance. */ public BlockingReadTimeoutException(Throwable cause) { initCause(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/queue/BufferedWriteHandler.java000066400000000000000000000351211225554127700322400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.queue; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioSocketChannelConfig; import org.jboss.netty.util.HashedWheelTimer; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; /** * Emulates buffered write operation. This handler stores all write requests * into an unbounded {@link Queue} and flushes them to the downstream when * {@link #flush()} method is called. *

* Here is an example that demonstrates the usage: *

 * BufferedWriteHandler bufferedWriter = new BufferedWriteHandler();
 * ChannelPipeline p = ...;
 * p.addFirst("buffer", bufferedWriter);
 *
 * ...
 *
 * Channel ch = ...;
 *
 * // msg1, 2, and 3 are stored in the queue of bufferedWriter.
 * ch.write(msg1);
 * ch.write(msg2);
 * ch.write(msg3);
 *
 * // and will be flushed on request.
 * bufferedWriter.flush();
 * 
* *

Auto-flush

* The write request queue is automatically flushed when the associated * {@link Channel} is disconnected or closed. However, it does not flush the * queue otherwise. It means you have to call {@link #flush()} before the size * of the queue increases too much. You can implement your own auto-flush * strategy by extending this handler: *
 * public class AutoFlusher extends {@link BufferedWriteHandler} {
 *
 *     private final AtomicLong bufferSize = new AtomicLong();
 *
 *     {@literal @Override}
 *     public void writeRequested({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         super.writeRequested(ctx, e);
 *
 *         {@link ChannelBuffer} data = ({@link ChannelBuffer}) e.getMessage();
 *         int newBufferSize = bufferSize.addAndGet(data.readableBytes());
 *
 *         // Flush the queue if it gets larger than 8KiB.
 *         if (newBufferSize > 8192) {
 *             flush();
 *             bufferSize.set(0);
 *         }
 *     }
 * }
 * 
* *

Consolidate on flush

* * If there are two or more write requests in the queue and all their message * type is {@link ChannelBuffer}, they can be merged into a single write request * to save the number of system calls. *
 * BEFORE consolidation:            AFTER consolidation:
 * +-------+-------+-------+        +-------------+
 * | Req C | Req B | Req A |------\\| Request ABC |
 * | "789" | "456" | "123" |------//| "123456789" |
 * +-------+-------+-------+        +-------------+
 * 
* This feature is disabled by default. You can override the default when you * create this handler or call {@link #flush(boolean)}. If you specified * {@code true} when you call the constructor, calling {@link #flush()} will * always consolidate the queue. Otherwise, you have to call * {@link #flush(boolean)} with {@code true} to enable this feature for each * flush. *

* The disadvantage of consolidation is that the {@link ChannelFuture} and its * {@link ChannelFutureListener}s associated with the original write requests * might be notified later than when they are actually written out. They will * always be notified when the consolidated write request is fully written. *

* The following example implements the consolidation strategy that reduces * the number of write requests based on the writability of a channel: *

 * public class ConsolidatingAutoFlusher extends {@link BufferedWriteHandler} {
 *
 *     public ConsolidatingAutoFlusher() {
 *         // Enable consolidation by default.
 *         super(true);
 *     }
 *
 *     {@literal @Override}
 *     public void channelOpen({@link ChannelHandlerContext} ctx, {@link ChannelStateEvent} e) throws Exception {
 *         {@link ChannelConfig} cfg = e.getChannel().getConfig();
 *         if (cfg instanceof {@link NioSocketChannelConfig}) {
 *             // Lower the watermark to increase the chance of consolidation.
 *             cfg.setWriteBufferLowWaterMark(0);
 *         }
 *         super.channelOpen(e);
 *     }
 *
 *     {@literal @Override}
 *     public void writeRequested({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) throws Exception {
 *         super.writeRequested(ctx, et);
 *         if (e.getChannel().isWritable()) {
 *             flush();
 *         }
 *     }
 *
 *     {@literal @Override}
 *     public void channelInterestChanged(
 *             {@link ChannelHandlerContext} ctx, {@link ChannelStateEvent} e) throws Exception {
 *         if (e.getChannel().isWritable()) {
 *             flush();
 *         }
 *     }
 * }
 * 
* *

Prioritized Writes

* * You can implement prioritized writes by specifying an unbounded priority * queue in the constructor of this handler. It will be required to design * the proper strategy to determine how often {@link #flush()} should be called. * For example, you could call {@link #flush()} periodically, using * {@link HashedWheelTimer} every second. * @apiviz.landmark */ public class BufferedWriteHandler extends SimpleChannelHandler implements LifeCycleAwareChannelHandler { private final Queue queue; private final boolean consolidateOnFlush; private volatile ChannelHandlerContext ctx; private final AtomicBoolean flush = new AtomicBoolean(false); /** * Creates a new instance with the default unbounded {@link BlockingQueue} * implementation and without buffer consolidation. */ public BufferedWriteHandler() { this(false); } /** * Creates a new instance with the specified thread-safe unbounded * {@link Queue} and without buffer consolidation. Please note that * specifying a bounded {@link Queue} or a thread-unsafe {@link Queue} will * result in an unspecified behavior. */ public BufferedWriteHandler(Queue queue) { this(queue, false); } /** * Creates a new instance with {@link ConcurrentLinkedQueue} * * @param consolidateOnFlush * {@code true} if and only if the buffered write requests are merged * into a single write request on {@link #flush()} */ public BufferedWriteHandler(boolean consolidateOnFlush) { this(new ConcurrentLinkedQueue(), consolidateOnFlush); } /** * Creates a new instance with the specified thread-safe unbounded * {@link Queue}. Please note that specifying a bounded {@link Queue} or * a thread-unsafe {@link Queue} will result in an unspecified behavior. * * @param consolidateOnFlush * {@code true} if and only if the buffered write requests are merged * into a single write request on {@link #flush()} */ public BufferedWriteHandler(Queue queue, boolean consolidateOnFlush) { if (queue == null) { throw new NullPointerException("queue"); } this.queue = queue; this.consolidateOnFlush = consolidateOnFlush; } public boolean isConsolidateOnFlush() { return consolidateOnFlush; } /** * Returns the queue which stores the write requests. The default * implementation returns the queue which was specified in the constructor. */ protected Queue getQueue() { return queue; } /** * Sends the queued write requests to the downstream. */ public void flush() { flush(consolidateOnFlush); } /** * Sends the queued write requests to the downstream. * * @param consolidateOnFlush * {@code true} if and only if the buffered write requests are merged * into a single write request */ public void flush(boolean consolidateOnFlush) { final ChannelHandlerContext ctx = this.ctx; if (ctx == null) { // No write request was made. return; } Channel channel = ctx.getChannel(); boolean acquired; // use CAS to see if the have flush already running, if so we don't need to take further actions if (acquired = flush.compareAndSet(false, true)) { final Queue queue = getQueue(); if (consolidateOnFlush) { if (queue.isEmpty()) { flush.set(false); return; } List pendingWrites = new ArrayList(); for (;;) { MessageEvent e = queue.poll(); if (e == null) { break; } if (!(e.getMessage() instanceof ChannelBuffer)) { if ((pendingWrites = consolidatedWrite(pendingWrites)) == null) { pendingWrites = new ArrayList(); } ctx.sendDownstream(e); } else { pendingWrites.add(e); } } consolidatedWrite(pendingWrites); } else { for (;;) { MessageEvent e = queue.poll(); if (e == null) { break; } ctx.sendDownstream(e); } } flush.set(false); } if (acquired && (!channel.isConnected() || channel.isWritable() && !queue.isEmpty())) { flush(consolidateOnFlush); } } private List consolidatedWrite(final List pendingWrites) { final int size = pendingWrites.size(); if (size == 1) { ctx.sendDownstream(pendingWrites.remove(0)); return pendingWrites; } if (size == 0) { return pendingWrites; } ChannelBuffer[] data = new ChannelBuffer[size]; for (int i = 0; i < data.length; i ++) { data[i] = (ChannelBuffer) pendingWrites.get(i).getMessage(); } ChannelBuffer composite = ChannelBuffers.wrappedBuffer(data); ChannelFuture future = Channels.future(ctx.getChannel()); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { for (MessageEvent e: pendingWrites) { e.getFuture().setSuccess(); } } else { Throwable cause = future.getCause(); for (MessageEvent e: pendingWrites) { e.getFuture().setFailure(cause); } } } }); Channels.write(ctx, future, composite); return null; } /** * Stores all write requests to the queue so that they are actually written * on {@link #flush()}. */ @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (this.ctx == null) { this.ctx = ctx; } else { assert this.ctx == ctx; } getQueue().add(e); } @Override public void disconnectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { try { flush(consolidateOnFlush); } finally { ctx.sendDownstream(e); } } @Override public void closeRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { try { flush(consolidateOnFlush); } finally { ctx.sendDownstream(e); } } /** * Fail all buffered writes that are left. See * #308 for more details. */ public void afterRemove(ChannelHandlerContext ctx) throws Exception { Throwable cause = null; for (;;) { MessageEvent ev = queue.poll(); if (ev == null) { break; } if (cause == null) { cause = new IOException("Unable to flush message"); } ev.getFuture().setFailure(cause); } if (cause != null) { Channels.fireExceptionCaughtLater(ctx.getChannel(), cause); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/queue/package-info.java000066400000000000000000000015471225554127700305360ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * The special-purpose handlers that store an event into an internal queue * instead of propagating the event immediately. * * @apiviz.exclude \.channel\. * @apiviz.exclude Exception$ */ package org.jboss.netty.handler.queue; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ssl/000077500000000000000000000000001225554127700250155ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ssl/ImmediateExecutor.java000066400000000000000000000021471225554127700313010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import java.util.concurrent.Executor; /** * {@link Executor} which executes the command in the caller thread. */ public final class ImmediateExecutor implements Executor { /** * The default instance. */ public static final ImmediateExecutor INSTANCE = new ImmediateExecutor(); public void execute(Runnable command) { command.run(); } private ImmediateExecutor() { // should use static instance } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ssl/NotSslRecordException.java000066400000000000000000000026501225554127700321230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import javax.net.ssl.SSLException; /** * Special {@link SSLException} which will get thrown if a packet is * received that not looks like a TLS/SSL record. A user can check for * this {@link NotSslRecordException} and so detect if one peer tries to * use secure and the other plain connection. * * */ public class NotSslRecordException extends SSLException { private static final long serialVersionUID = -4316784434770656841L; public NotSslRecordException() { super(""); } public NotSslRecordException(String message) { super(message); } public NotSslRecordException(Throwable cause) { super(cause); } public NotSslRecordException(String message, Throwable cause) { super(message, cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ssl/SslBufferPool.java000066400000000000000000000101051225554127700304020ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import javax.net.ssl.SSLEngine; import java.nio.ByteBuffer; /** * A {@link ByteBuffer} pool dedicated for {@link SslHandler} performance * improvement. *

* In most cases, you won't need to create a new pool instance because * {@link SslHandler} has a default pool instance internally. *

* The reason why {@link SslHandler} requires a buffer pool is because the * current {@link SSLEngine} implementation always requires a 17KiB buffer for * every 'wrap' and 'unwrap' operation. In most cases, the actual size of the * required buffer is much smaller than that, and therefore allocating a 17KiB * buffer for every 'wrap' and 'unwrap' operation wastes a lot of memory * bandwidth, resulting in the application performance degradation. */ public class SslBufferPool { // Add 1024 as a room for compressed data and another 1024 for Apache Harmony compatibility. private static final int MAX_PACKET_SIZE = 16665 + 2048; private static final int DEFAULT_POOL_SIZE = MAX_PACKET_SIZE * 1024; private final ByteBuffer[] pool; private final int maxBufferCount; private int index; /** * Creates a new buffer pool whose size is {@code 18113536}, which can * hold {@code 1024} buffers. */ public SslBufferPool() { this(DEFAULT_POOL_SIZE); } /** * Creates a new buffer pool. * * @param maxPoolSize the maximum number of bytes that this pool can hold */ public SslBufferPool(int maxPoolSize) { if (maxPoolSize <= 0) { throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize); } int maxBufferCount = maxPoolSize / MAX_PACKET_SIZE; if (maxPoolSize % MAX_PACKET_SIZE != 0) { maxBufferCount ++; } pool = new ByteBuffer[maxBufferCount]; this.maxBufferCount = maxBufferCount; } /** * Returns the maximum size of this pool in byte unit. The returned value * can be somewhat different from what was specified in the constructor. */ public int getMaxPoolSize() { return maxBufferCount * MAX_PACKET_SIZE; } /** * Returns the number of bytes which were allocated but have not been * acquired yet. You can estimate how optimal the specified maximum pool * size is from this value. If it keeps returning {@code 0}, it means the * pool is getting exhausted. If it keeps returns a unnecessarily big * value, it means the pool is wasting the heap space. */ public synchronized int getUnacquiredPoolSize() { return index * MAX_PACKET_SIZE; } /** * Acquire a new {@link ByteBuffer} out of the {@link SslBufferPool} * */ public synchronized ByteBuffer acquireBuffer() { if (index == 0) { return ByteBuffer.allocate(MAX_PACKET_SIZE); } else { return (ByteBuffer) pool[-- index].clear(); } } /** * Will get removed. Please use {@link #acquireBuffer()} * */ @Deprecated ByteBuffer acquire() { return acquireBuffer(); } /** * Release a previous acquired {@link ByteBuffer} */ public synchronized void releaseBuffer(ByteBuffer buffer) { if (index < maxBufferCount) { pool[index ++] = buffer; } } /** * @deprecated Use {@link #releaseBuffer(ByteBuffer)} */ @Deprecated void release(ByteBuffer buffer) { releaseBuffer(buffer); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ssl/SslHandler.java000066400000000000000000002006001225554127700277150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.channel.DownstreamMessageEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import org.jboss.netty.util.internal.DetectionUtil; import org.jboss.netty.util.internal.NonReentrantLock; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; import javax.net.ssl.SSLException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.DatagramChannel; import java.nio.channels.SocketChannel; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.regex.Pattern; import static org.jboss.netty.channel.Channels.*; /** * Adds SSL * · TLS and StartTLS support to a {@link Channel}. Please refer * to the "SecureChat" example in the distribution or the web * site for the detailed usage. * *

Beginning the handshake

*

* You must make sure not to write a message while the * {@linkplain #handshake() handshake} is in progress unless you are * renegotiating. You will be notified by the {@link ChannelFuture} which is * returned by the {@link #handshake()} method when the handshake * process succeeds or fails. * *

Handshake

*

* If {@link #isIssueHandshake()} is {@code false} * (default) you will need to take care of calling {@link #handshake()} by your own. In most * situations were {@link SslHandler} is used in 'client mode' you want to issue a handshake once * the connection was established. if {@link #setIssueHandshake(boolean)} is set to {@code true} * you don't need to worry about this as the {@link SslHandler} will take care of it. *

* *

Renegotiation

*

* If {@link #isEnableRenegotiation() enableRenegotiation} is {@code true} * (default) and the initial handshake has been done successfully, you can call * {@link #handshake()} to trigger the renegotiation. *

* If {@link #isEnableRenegotiation() enableRenegotiation} is {@code false}, * an attempt to trigger renegotiation will result in the connection closure. *

* Please note that TLS renegotiation had a security issue before. If your * runtime environment did not fix it, please make sure to disable TLS * renegotiation by calling {@link #setEnableRenegotiation(boolean)} with * {@code false}. For more information, please refer to the following documents: *

* *

Closing the session

*

* To close the SSL session, the {@link #close()} method should be * called to send the {@code close_notify} message to the remote peer. One * exception is when you close the {@link Channel} - {@link SslHandler} * intercepts the close request and send the {@code close_notify} message * before the channel closure automatically. Once the SSL session is closed, * it is not reusable, and consequently you should create a new * {@link SslHandler} with a new {@link SSLEngine} as explained in the * following section. * *

Restarting the session

*

* To restart the SSL session, you must remove the existing closed * {@link SslHandler} from the {@link ChannelPipeline}, insert a new * {@link SslHandler} with a new {@link SSLEngine} into the pipeline, * and start the handshake process as described in the first section. * *

Implementing StartTLS

*

* StartTLS is the * communication pattern that secures the wire in the middle of the plaintext * connection. Please note that it is different from SSL · TLS, that * secures the wire from the beginning of the connection. Typically, StartTLS * is composed of three steps: *

    *
  1. Client sends a StartTLS request to server.
  2. *
  3. Server sends a StartTLS response to client.
  4. *
  5. Client begins SSL handshake.
  6. *
* If you implement a server, you need to: *
    *
  1. create a new {@link SslHandler} instance with {@code startTls} flag set * to {@code true},
  2. *
  3. insert the {@link SslHandler} to the {@link ChannelPipeline}, and
  4. *
  5. write a StartTLS response.
  6. *
* Please note that you must insert {@link SslHandler} before sending * the StartTLS response. Otherwise the client can send begin SSL handshake * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing * data corruption. *

* The client-side implementation is much simpler. *

    *
  1. Write a StartTLS request,
  2. *
  3. wait for the StartTLS response,
  4. *
  5. create a new {@link SslHandler} instance with {@code startTls} flag set * to {@code false},
  6. *
  7. insert the {@link SslHandler} to the {@link ChannelPipeline}, and
  8. *
  9. Initiate SSL handshake by calling {@link SslHandler#handshake()}.
  10. *
* *

Known issues

*

* Because of a known issue with the current implementation of the SslEngine that comes * with Java it may be possible that you see blocked IO-Threads while a full GC is done. *

* So if you are affected you can workaround this problem by adjust the cache settings * like shown below: * *

 *     SslContext context = ...;
 *     context.getServerSessionContext().setSessionCacheSize(someSaneSize);
 *     context.getServerSessionContext().setSessionTime(someSameTimeout);
 * 
*

* What values to use here depends on the nature of your application and should be set * based on monitoring and debugging of it. * For more details see * #832 in our issue tracker. * @apiviz.landmark * @apiviz.uses org.jboss.netty.handler.ssl.SslBufferPool */ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslHandler.class); private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile( "^.*(?:Socket|Datagram|Sctp|Udt)Channel.*$"); private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile( "^.*(?:connection.*(?:reset|closed|abort|broken)|broken.*pipe).*$", Pattern.CASE_INSENSITIVE); private static SslBufferPool defaultBufferPool; /** * Returns the default {@link SslBufferPool} used when no pool is * specified in the constructor. */ public static synchronized SslBufferPool getDefaultBufferPool() { if (defaultBufferPool == null) { defaultBufferPool = new SslBufferPool(); } return defaultBufferPool; } private volatile ChannelHandlerContext ctx; private final SSLEngine engine; private final SslBufferPool bufferPool; private final Executor delegatedTaskExecutor; private final boolean startTls; private volatile boolean enableRenegotiation = true; final Object handshakeLock = new Object(); private boolean handshaking; private volatile boolean handshaken; private volatile ChannelFuture handshakeFuture; @SuppressWarnings("UnusedDeclaration") private volatile int sentFirstMessage; @SuppressWarnings("UnusedDeclaration") private volatile int sentCloseNotify; @SuppressWarnings("UnusedDeclaration") private volatile int closedOutboundAndChannel; private static final AtomicIntegerFieldUpdater SENT_FIRST_MESSAGE_UPDATER = AtomicIntegerFieldUpdater.newUpdater(SslHandler.class, "sentFirstMessage"); private static final AtomicIntegerFieldUpdater SENT_CLOSE_NOTIFY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(SslHandler.class, "sentCloseNotify"); private static final AtomicIntegerFieldUpdater CLOSED_OUTBOUND_AND_CHANNEL_UPDATER = AtomicIntegerFieldUpdater.newUpdater(SslHandler.class, "closedOutboundAndChannel"); int ignoreClosedChannelException; final Object ignoreClosedChannelExceptionLock = new Object(); private final Queue pendingUnencryptedWrites = new LinkedList(); private final NonReentrantLock pendingUnencryptedWritesLock = new NonReentrantLock(); private final Queue pendingEncryptedWrites = new ConcurrentLinkedQueue(); private final NonReentrantLock pendingEncryptedWritesLock = new NonReentrantLock(); private volatile boolean issueHandshake; private final SSLEngineInboundCloseFuture sslEngineCloseFuture = new SSLEngineInboundCloseFuture(); private boolean closeOnSSLException; private int packetLength; private final Timer timer; private final long handshakeTimeoutInMillis; private Timeout handshakeTimeout; /** * Creates a new instance. * * @param engine the {@link SSLEngine} this handler will use */ public SslHandler(SSLEngine engine) { this(engine, getDefaultBufferPool(), ImmediateExecutor.INSTANCE); } /** * Creates a new instance. * * @param engine the {@link SSLEngine} this handler will use * @param bufferPool the {@link SslBufferPool} where this handler will * acquire the buffers required by the {@link SSLEngine} */ public SslHandler(SSLEngine engine, SslBufferPool bufferPool) { this(engine, bufferPool, ImmediateExecutor.INSTANCE); } /** * Creates a new instance. * * @param engine the {@link SSLEngine} this handler will use * @param startTls {@code true} if the first write request shouldn't be * encrypted by the {@link SSLEngine} */ public SslHandler(SSLEngine engine, boolean startTls) { this(engine, getDefaultBufferPool(), startTls); } /** * Creates a new instance. * * @param engine the {@link SSLEngine} this handler will use * @param bufferPool the {@link SslBufferPool} where this handler will * acquire the buffers required by the {@link SSLEngine} * @param startTls {@code true} if the first write request shouldn't be * encrypted by the {@link SSLEngine} */ public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls) { this(engine, bufferPool, startTls, ImmediateExecutor.INSTANCE); } /** * Creates a new instance. * * @param engine * the {@link SSLEngine} this handler will use * @param delegatedTaskExecutor * the {@link Executor} which will execute the delegated task * that {@link SSLEngine#getDelegatedTask()} will return */ public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) { this(engine, getDefaultBufferPool(), delegatedTaskExecutor); } /** * Creates a new instance. * * @param engine * the {@link SSLEngine} this handler will use * @param bufferPool * the {@link SslBufferPool} where this handler will acquire * the buffers required by the {@link SSLEngine} * @param delegatedTaskExecutor * the {@link Executor} which will execute the delegated task * that {@link SSLEngine#getDelegatedTask()} will return */ public SslHandler(SSLEngine engine, SslBufferPool bufferPool, Executor delegatedTaskExecutor) { this(engine, bufferPool, false, delegatedTaskExecutor); } /** * Creates a new instance. * * @param engine * the {@link SSLEngine} this handler will use * @param startTls * {@code true} if the first write request shouldn't be encrypted * by the {@link SSLEngine} * @param delegatedTaskExecutor * the {@link Executor} which will execute the delegated task * that {@link SSLEngine#getDelegatedTask()} will return */ public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) { this(engine, getDefaultBufferPool(), startTls, delegatedTaskExecutor); } /** * Creates a new instance. * * @param engine * the {@link SSLEngine} this handler will use * @param bufferPool * the {@link SslBufferPool} where this handler will acquire * the buffers required by the {@link SSLEngine} * @param startTls * {@code true} if the first write request shouldn't be encrypted * by the {@link SSLEngine} * @param delegatedTaskExecutor * the {@link Executor} which will execute the delegated task * that {@link SSLEngine#getDelegatedTask()} will return */ public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor) { this(engine, bufferPool, startTls, delegatedTaskExecutor, null, 0); } /** * Creates a new instance. * * @param engine * the {@link SSLEngine} this handler will use * @param bufferPool * the {@link SslBufferPool} where this handler will acquire * the buffers required by the {@link SSLEngine} * @param startTls * {@code true} if the first write request shouldn't be encrypted * by the {@link SSLEngine} * @param delegatedTaskExecutor * the {@link Executor} which will execute the delegated task * that {@link SSLEngine#getDelegatedTask()} will return * @param timer * the {@link Timer} which will be used to process the timeout of the {@link #handshake()}. * Be aware that the given {@link Timer} will not get stopped automaticly, so it is up to you to cleanup * once you not need it anymore * @param handshakeTimeoutInMillis * the time in milliseconds after whic the {@link #handshake()} will be failed, and so the future notified * */ public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor, Timer timer, long handshakeTimeoutInMillis) { if (engine == null) { throw new NullPointerException("engine"); } if (bufferPool == null) { throw new NullPointerException("bufferPool"); } if (delegatedTaskExecutor == null) { throw new NullPointerException("delegatedTaskExecutor"); } if (timer == null && handshakeTimeoutInMillis > 0) { throw new IllegalArgumentException("No Timer was given but a handshakeTimeoutInMillis, need both or none"); } this.engine = engine; this.bufferPool = bufferPool; this.delegatedTaskExecutor = delegatedTaskExecutor; this.startTls = startTls; this.timer = timer; this.handshakeTimeoutInMillis = handshakeTimeoutInMillis; } /** * Returns the {@link SSLEngine} which is used by this handler. */ public SSLEngine getEngine() { return engine; } /** * Starts an SSL / TLS handshake for the specified channel. * * @return a {@link ChannelFuture} which is notified when the handshake * succeeds or fails. */ public ChannelFuture handshake() { synchronized (handshakeLock) { if (handshaken && !isEnableRenegotiation()) { throw new IllegalStateException("renegotiation disabled"); } final ChannelHandlerContext ctx = this.ctx; final Channel channel = ctx.getChannel(); ChannelFuture handshakeFuture; Exception exception = null; if (handshaking) { return this.handshakeFuture; } handshaking = true; try { engine.beginHandshake(); runDelegatedTasks(); handshakeFuture = this.handshakeFuture = future(channel); if (handshakeTimeoutInMillis > 0) { handshakeTimeout = timer.newTimeout(new TimerTask() { public void run(Timeout timeout) throws Exception { ChannelFuture future = SslHandler.this.handshakeFuture; if (future != null && future.isDone()) { return; } setHandshakeFailure(channel, new SSLException("Handshake did not complete within " + handshakeTimeoutInMillis + "ms")); } }, handshakeTimeoutInMillis, TimeUnit.MILLISECONDS); } } catch (Exception e) { handshakeFuture = this.handshakeFuture = failedFuture(channel, e); exception = e; } if (exception == null) { // Began handshake successfully. try { final ChannelFuture hsFuture = handshakeFuture; wrapNonAppData(ctx, channel).addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { Throwable cause = future.getCause(); hsFuture.setFailure(cause); fireExceptionCaught(ctx, cause); if (closeOnSSLException) { Channels.close(ctx, future(channel)); } } } }); } catch (SSLException e) { handshakeFuture.setFailure(e); fireExceptionCaught(ctx, e); if (closeOnSSLException) { Channels.close(ctx, future(channel)); } } } else { // Failed to initiate handshake. fireExceptionCaught(ctx, exception); if (closeOnSSLException) { Channels.close(ctx, future(channel)); } } return handshakeFuture; } } /** * @deprecated Use {@link #handshake()} instead. */ @Deprecated public ChannelFuture handshake(@SuppressWarnings("unused") Channel channel) { return handshake(); } /** * Sends an SSL {@code close_notify} message to the specified channel and * destroys the underlying {@link SSLEngine}. */ public ChannelFuture close() { ChannelHandlerContext ctx = this.ctx; Channel channel = ctx.getChannel(); try { engine.closeOutbound(); return wrapNonAppData(ctx, channel); } catch (SSLException e) { fireExceptionCaught(ctx, e); if (closeOnSSLException) { Channels.close(ctx, future(channel)); } return failedFuture(channel, e); } } /** * @deprecated Use {@link #close()} instead. */ @Deprecated public ChannelFuture close(@SuppressWarnings("unused") Channel channel) { return close(); } /** * Returns {@code true} if and only if TLS renegotiation is enabled. */ public boolean isEnableRenegotiation() { return enableRenegotiation; } /** * Enables or disables TLS renegotiation. */ public void setEnableRenegotiation(boolean enableRenegotiation) { this.enableRenegotiation = enableRenegotiation; } /** * Enables or disables the automatic handshake once the {@link Channel} is * connected. The value will only have affect if its set before the * {@link Channel} is connected. */ public void setIssueHandshake(boolean issueHandshake) { this.issueHandshake = issueHandshake; } /** * Returns {@code true} if the automatic handshake is enabled */ public boolean isIssueHandshake() { return issueHandshake; } /** * Return the {@link ChannelFuture} that will get notified if the inbound of the {@link SSLEngine} will get closed. * * This method will return the same {@link ChannelFuture} all the time. * * For more informations see the apidocs of {@link SSLEngine} * */ public ChannelFuture getSSLEngineInboundCloseFuture() { return sslEngineCloseFuture; } /** * Return the timeout (in ms) after which the {@link ChannelFuture} of {@link #handshake()} will be failed, while * a handshake is in progress */ public long getHandshakeTimeout() { return handshakeTimeoutInMillis; } /** * If set to {@code true}, the {@link Channel} will automatically get closed * one a {@link SSLException} was caught. This is most times what you want, as after this * its almost impossible to recover. * * Anyway the default is {@code false} to not break compatibility with older releases. This * will be changed to {@code true} in the next major release. * */ public void setCloseOnSSLException(boolean closeOnSslException) { if (ctx != null) { throw new IllegalStateException("Can only get changed before attached to ChannelPipeline"); } closeOnSSLException = closeOnSslException; } public boolean getCloseOnSSLException() { return closeOnSSLException; } public void handleDownstream( final ChannelHandlerContext context, final ChannelEvent evt) throws Exception { if (evt instanceof ChannelStateEvent) { ChannelStateEvent e = (ChannelStateEvent) evt; switch (e.getState()) { case OPEN: case CONNECTED: case BOUND: if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) { closeOutboundAndChannel(context, e); return; } } } if (!(evt instanceof MessageEvent)) { context.sendDownstream(evt); return; } MessageEvent e = (MessageEvent) evt; if (!(e.getMessage() instanceof ChannelBuffer)) { context.sendDownstream(evt); return; } // Do not encrypt the first write request if this handler is // created with startTLS flag turned on. if (startTls && SENT_FIRST_MESSAGE_UPDATER.compareAndSet(this, 0, 1)) { context.sendDownstream(evt); return; } // Otherwise, all messages are encrypted. ChannelBuffer msg = (ChannelBuffer) e.getMessage(); PendingWrite pendingWrite; if (msg.readable()) { pendingWrite = new PendingWrite(evt.getFuture(), msg.toByteBuffer(msg.readerIndex(), msg.readableBytes())); } else { pendingWrite = new PendingWrite(evt.getFuture(), null); } pendingUnencryptedWritesLock.lock(); try { pendingUnencryptedWrites.add(pendingWrite); } finally { pendingUnencryptedWritesLock.unlock(); } wrap(context, evt.getChannel()); } private void cancelHandshakeTimeout() { if (handshakeTimeout != null) { // cancel the task as we will fail the handshake future now handshakeTimeout.cancel(); } } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Make sure the handshake future is notified when a connection has // been closed during handshake. synchronized (handshakeLock) { if (handshaking) { cancelHandshakeTimeout(); handshakeFuture.setFailure(new ClosedChannelException()); } } try { super.channelDisconnected(ctx, e); } finally { unwrap(ctx, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0); engine.closeOutbound(); if (sentCloseNotify == 0 && handshaken) { try { engine.closeInbound(); } catch (SSLException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to clean up SSLEngine.", ex); } } } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Throwable cause = e.getCause(); if (cause instanceof IOException) { if (cause instanceof ClosedChannelException) { synchronized (ignoreClosedChannelExceptionLock) { if (ignoreClosedChannelException > 0) { ignoreClosedChannelException --; if (logger.isDebugEnabled()) { logger.debug( "Swallowing an exception raised while " + "writing non-app data", cause); } return; } } } else { if (ignoreException(cause)) { return; } } } ctx.sendUpstream(e); } /** * Checks if the given {@link Throwable} can be ignore and just "swallowed" * * When an ssl connection is closed a close_notify message is sent. * After that the peer also sends close_notify however, it's not mandatory to receive * the close_notify. The party who sent the initial close_notify can close the connection immediately * then the peer will get connection reset error. * */ private boolean ignoreException(Throwable t) { if (!(t instanceof SSLException) && t instanceof IOException && engine.isOutboundDone()) { String message = String.valueOf(t.getMessage()).toLowerCase(); // first try to match connection reset / broke peer based on the regex. This is the fastest way // but may fail on different jdk impls or OS's if (IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) { return true; } // Inspect the StackTraceElements to see if it was a connection reset / broken pipe or not StackTraceElement[] elements = t.getStackTrace(); for (StackTraceElement element: elements) { String classname = element.getClassName(); String methodname = element.getMethodName(); // skip all classes that belong to the io.netty package if (classname.startsWith("org.jboss.netty.")) { continue; } // check if the method name is read if not skip it if (!"read".equals(methodname)) { continue; } // This will also match against SocketInputStream which is used by openjdk 7 and maybe // also others if (IGNORABLE_CLASS_IN_STACK.matcher(classname).matches()) { return true; } try { // No match by now.. Try to load the class via classloader and inspect it. // This is mainly done as other JDK implementations may differ in name of // the impl. Class clazz = getClass().getClassLoader().loadClass(classname); if (SocketChannel.class.isAssignableFrom(clazz) || DatagramChannel.class.isAssignableFrom(clazz)) { return true; } // also match against SctpChannel via String matching as it may not present. if (DetectionUtil.javaVersion() >= 7 && "com.sun.nio.sctp.SctpChannel".equals(clazz.getSuperclass().getName())) { return true; } } catch (ClassNotFoundException e) { // This should not happen just ignore } } } return false; } /** * Returns {@code true} if the given {@link ChannelBuffer} is encrypted. Be aware that this method * will not increase the readerIndex of the given {@link ChannelBuffer}. * * @param buffer * The {@link ChannelBuffer} to read from. Be aware that it must have at least 5 bytes to read, * otherwise it will throw an {@link IllegalArgumentException}. * @return encrypted * {@code true} if the {@link ChannelBuffer} is encrypted, {@code false} otherwise. * @throws IllegalArgumentException * Is thrown if the given {@link ChannelBuffer} has not at least 5 bytes to read. */ public static boolean isEncrypted(ChannelBuffer buffer) { return getEncryptedPacketLength(buffer, buffer.readerIndex()) != -1; } /** * Return how much bytes can be read out of the encrypted data. Be aware that this method will not increase * the readerIndex of the given {@link ChannelBuffer}. * * @param buffer * The {@link ChannelBuffer} to read from. Be aware that it must have at least 5 bytes to read, * otherwise it will throw an {@link IllegalArgumentException}. * @return length * The length of the encrypted packet that is included in the buffer. This will * return {@code -1} if the given {@link ChannelBuffer} is not encrypted at all. * @throws IllegalArgumentException * Is thrown if the given {@link ChannelBuffer} has not at least 5 bytes to read. */ private static int getEncryptedPacketLength(ChannelBuffer buffer, int offset) { int packetLength = 0; // SSLv3 or TLS - Check ContentType boolean tls; switch (buffer.getUnsignedByte(offset)) { case 20: // change_cipher_spec case 21: // alert case 22: // handshake case 23: // application_data tls = true; break; default: // SSLv2 or bad data tls = false; } if (tls) { // SSLv3 or TLS - Check ProtocolVersion int majorVersion = buffer.getUnsignedByte(offset + 1); if (majorVersion == 3) { // SSLv3 or TLS packetLength = (getShort(buffer, offset + 3) & 0xFFFF) + 5; if (packetLength <= 5) { // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data) tls = false; } } else { // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data) tls = false; } } if (!tls) { // SSLv2 or bad data - Check the version boolean sslv2 = true; int headerLength = (buffer.getUnsignedByte(offset) & 0x80) != 0 ? 2 : 3; int majorVersion = buffer.getUnsignedByte(offset + headerLength + 1); if (majorVersion == 2 || majorVersion == 3) { // SSLv2 if (headerLength == 2) { packetLength = (getShort(buffer, offset) & 0x7FFF) + 2; } else { packetLength = (getShort(buffer, offset) & 0x3FFF) + 3; } if (packetLength <= headerLength) { sslv2 = false; } } else { sslv2 = false; } if (!sslv2) { return -1; } } return packetLength; } @Override protected Object decode( final ChannelHandlerContext ctx, Channel channel, ChannelBuffer in) throws Exception { final int startOffset = in.readerIndex(); final int endOffset = in.writerIndex(); int offset = startOffset; // If we calculated the length of the current SSL record before, use that information. if (packetLength > 0) { if (endOffset - startOffset < packetLength) { return null; } else { offset += packetLength; packetLength = 0; } } boolean nonSslRecord = false; for (;;) { final int readableBytes = endOffset - offset; if (readableBytes < 5) { break; } final int packetLength = getEncryptedPacketLength(in, offset); if (packetLength == -1) { nonSslRecord = true; break; } assert packetLength > 0; if (packetLength > readableBytes) { // wait until the whole packet can be read this.packetLength = packetLength; break; } offset += packetLength; } final int length = offset - startOffset; ChannelBuffer unwrapped = null; if (length > 0) { // The buffer contains one or more full SSL records. // Slice out the whole packet so unwrap will only be called with complete packets. // Also directly reset the packetLength. This is needed as unwrap(..) may trigger // decode(...) again via: // 1) unwrap(..) is called // 2) wrap(...) is called from within unwrap(...) // 3) wrap(...) calls unwrapLater(...) // 4) unwrapLater(...) calls decode(...) // // See https://github.com/netty/netty/issues/1534 unwrapped = unwrap(ctx, channel, in, startOffset, length); } if (nonSslRecord) { // Not an SSL/TLS packet NotSslRecordException e = new NotSslRecordException( "not an SSL/TLS record: " + ChannelBuffers.hexDump(in)); in.skipBytes(in.readableBytes()); if (closeOnSSLException) { // first trigger the exception and then close the channel fireExceptionCaught(ctx, e); Channels.close(ctx, future(channel)); // just return null as we closed the channel before, that // will take care of cleanup etc return null; } else { throw e; } } return unwrapped; } /** * Reads a big-endian short integer from the buffer. Please note that we do not use * {@link ChannelBuffer#getShort(int)} because it might be a little-endian buffer. */ private static short getShort(ChannelBuffer buf, int offset) { return (short) (buf.getByte(offset) << 8 | buf.getByte(offset + 1) & 0xFF); } private void wrap(ChannelHandlerContext context, Channel channel) throws SSLException { ChannelBuffer msg; ByteBuffer outNetBuf = bufferPool.acquireBuffer(); boolean success = true; boolean offered = false; boolean needsUnwrap = false; PendingWrite pendingWrite = null; try { loop: for (;;) { // Acquire a lock to make sure unencrypted data is polled // in order and their encrypted counterpart is offered in // order. pendingUnencryptedWritesLock.lock(); try { pendingWrite = pendingUnencryptedWrites.peek(); if (pendingWrite == null) { break; } ByteBuffer outAppBuf = pendingWrite.outAppBuf; if (outAppBuf == null) { // A write request with an empty buffer pendingUnencryptedWrites.remove(); offerEncryptedWriteRequest( new DownstreamMessageEvent( channel, pendingWrite.future, ChannelBuffers.EMPTY_BUFFER, channel.getRemoteAddress())); offered = true; } else { synchronized (handshakeLock) { SSLEngineResult result = null; try { result = engine.wrap(outAppBuf, outNetBuf); } finally { if (!outAppBuf.hasRemaining()) { pendingUnencryptedWrites.remove(); } } if (result.bytesProduced() > 0) { outNetBuf.flip(); int remaining = outNetBuf.remaining(); msg = ctx.getChannel().getConfig().getBufferFactory().getBuffer(remaining); // Transfer the bytes to the new ChannelBuffer using some safe method that will also // work with "non" heap buffers // // See https://github.com/netty/netty/issues/329 msg.writeBytes(outNetBuf); outNetBuf.clear(); ChannelFuture future; if (pendingWrite.outAppBuf.hasRemaining()) { // pendingWrite's future shouldn't be notified if // only partial data is written. future = succeededFuture(channel); } else { future = pendingWrite.future; } MessageEvent encryptedWrite = new DownstreamMessageEvent( channel, future, msg, channel.getRemoteAddress()); offerEncryptedWriteRequest(encryptedWrite); offered = true; } else if (result.getStatus() == Status.CLOSED) { // SSLEngine has been closed already. // Any further write attempts should be denied. success = false; break; } else { final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); handleRenegotiation(handshakeStatus); switch (handshakeStatus) { case NEED_WRAP: if (outAppBuf.hasRemaining()) { break; } else { break loop; } case NEED_UNWRAP: needsUnwrap = true; break loop; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: case NOT_HANDSHAKING: if (handshakeStatus == HandshakeStatus.FINISHED) { setHandshakeSuccess(channel); } if (result.getStatus() == Status.CLOSED) { success = false; } break loop; default: throw new IllegalStateException( "Unknown handshake status: " + handshakeStatus); } } } } } finally { pendingUnencryptedWritesLock.unlock(); } } } catch (SSLException e) { success = false; setHandshakeFailure(channel, e); throw e; } finally { bufferPool.releaseBuffer(outNetBuf); if (offered) { flushPendingEncryptedWrites(context); } if (!success) { IllegalStateException cause = new IllegalStateException("SSLEngine already closed"); // Check if we had a pendingWrite in process, if so we need to also notify as otherwise // the ChannelFuture will never get notified if (pendingWrite != null) { pendingWrite.future.setFailure(cause); } // Mark all remaining pending writes as failure if anything // wrong happened before the write requests are wrapped. // Please note that we do not call setFailure while a lock is // acquired, to avoid a potential dead lock. for (;;) { pendingUnencryptedWritesLock.lock(); try { pendingWrite = pendingUnencryptedWrites.poll(); if (pendingWrite == null) { break; } } finally { pendingUnencryptedWritesLock.unlock(); } pendingWrite.future.setFailure(cause); } } } if (needsUnwrap) { unwrap(context, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0); } } private void offerEncryptedWriteRequest(MessageEvent encryptedWrite) { final boolean locked = pendingEncryptedWritesLock.tryLock(); try { pendingEncryptedWrites.add(encryptedWrite); } finally { if (locked) { pendingEncryptedWritesLock.unlock(); } } } private void flushPendingEncryptedWrites(ChannelHandlerContext ctx) { while (!pendingEncryptedWrites.isEmpty()) { // Avoid possible dead lock and data integrity issue // which is caused by cross communication between more than one channel // in the same VM. if (!pendingEncryptedWritesLock.tryLock()) { return; } try { MessageEvent e; while ((e = pendingEncryptedWrites.poll()) != null) { ctx.sendDownstream(e); } } finally { pendingEncryptedWritesLock.unlock(); } // Other thread might have added more elements at this point, so we loop again if the queue got unempty. } } private ChannelFuture wrapNonAppData(ChannelHandlerContext ctx, Channel channel) throws SSLException { ChannelFuture future = null; ByteBuffer outNetBuf = bufferPool.acquireBuffer(); SSLEngineResult result; try { for (;;) { synchronized (handshakeLock) { result = engine.wrap(EMPTY_BUFFER, outNetBuf); } if (result.bytesProduced() > 0) { outNetBuf.flip(); ChannelBuffer msg = ctx.getChannel().getConfig().getBufferFactory().getBuffer(outNetBuf.remaining()); // Transfer the bytes to the new ChannelBuffer using some safe method that will also // work with "non" heap buffers // // See https://github.com/netty/netty/issues/329 msg.writeBytes(outNetBuf); outNetBuf.clear(); future = future(channel); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (future.getCause() instanceof ClosedChannelException) { synchronized (ignoreClosedChannelExceptionLock) { ignoreClosedChannelException ++; } } } }); write(ctx, future, msg); } final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); handleRenegotiation(handshakeStatus); switch (handshakeStatus) { case FINISHED: setHandshakeSuccess(channel); runDelegatedTasks(); break; case NEED_TASK: runDelegatedTasks(); break; case NEED_UNWRAP: if (!Thread.holdsLock(handshakeLock)) { // unwrap shouldn't be called when this method was // called by unwrap - unwrap will keep running after // this method returns. unwrap(ctx, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0); } break; case NOT_HANDSHAKING: case NEED_WRAP: break; default: throw new IllegalStateException( "Unexpected handshake status: " + handshakeStatus); } if (result.bytesProduced() == 0) { break; } } } catch (SSLException e) { setHandshakeFailure(channel, e); throw e; } finally { bufferPool.releaseBuffer(outNetBuf); } if (future == null) { future = succeededFuture(channel); } return future; } private ChannelBuffer unwrap( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, int offset, int length) throws SSLException { final ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length); final ByteBuffer outAppBuf = bufferPool.acquireBuffer(); final int bufferStartOffset = buffer.readerIndex(); final int inNetBufStartOffset = inNetBuf.position(); ChannelBuffer frame = null; try { boolean needsWrap = false; for (;;) { SSLEngineResult result; boolean needsHandshake = false; synchronized (handshakeLock) { if (!handshaken && !handshaking && !engine.getUseClientMode() && !engine.isInboundDone() && !engine.isOutboundDone()) { needsHandshake = true; } } if (needsHandshake) { handshake(); } synchronized (handshakeLock) { // Decrypt at least one record in the inbound network buffer. // It is impossible to consume no record here because we made sure the inbound network buffer // always contain at least one record in decode(). Therefore, if SSLEngine.unwrap() returns // BUFFER_OVERFLOW, it is always resolved by retrying after emptying the application buffer. for (;;) { try { result = engine.unwrap(inNetBuf, outAppBuf); switch (result.getStatus()) { case CLOSED: // notify about the CLOSED state of the SSLEngine. See #137 sslEngineCloseFuture.setClosed(); break; case BUFFER_OVERFLOW: // Flush the unwrapped data in the outAppBuf into frame and try again. // See the finally block. continue; } break; } finally { outAppBuf.flip(); // Sync the offset of the inbound buffer. buffer.readerIndex(bufferStartOffset + inNetBuf.position() - inNetBufStartOffset); // Copy the unwrapped data into a smaller buffer. if (outAppBuf.hasRemaining()) { if (frame == null) { frame = ctx.getChannel().getConfig().getBufferFactory().getBuffer(length); } frame.writeBytes(outAppBuf); } outAppBuf.clear(); } } final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); handleRenegotiation(handshakeStatus); switch (handshakeStatus) { case NEED_UNWRAP: break; case NEED_WRAP: wrapNonAppData(ctx, channel); break; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: setHandshakeSuccess(channel); needsWrap = true; continue; case NOT_HANDSHAKING: break; default: throw new IllegalStateException( "Unknown handshake status: " + handshakeStatus); } if (result.getStatus() == Status.BUFFER_UNDERFLOW || result.bytesConsumed() == 0 && result.bytesProduced() == 0) { break; } } } if (needsWrap) { // wrap() acquires pendingUnencryptedWrites first and then // handshakeLock. If handshakeLock is already hold by the // current thread, calling wrap() will lead to a dead lock // i.e. pendingUnencryptedWrites -> handshakeLock vs. // handshakeLock -> pendingUnencryptedLock -> handshakeLock // // There is also the same issue between pendingEncryptedWrites // and pendingUnencryptedWrites. if (!Thread.holdsLock(handshakeLock) && !pendingEncryptedWritesLock.isHeldByCurrentThread()) { wrap(ctx, channel); } } } catch (SSLException e) { setHandshakeFailure(channel, e); throw e; } finally { bufferPool.releaseBuffer(outAppBuf); } if (frame != null && frame.readable()) { return frame; } else { return null; } } private void handleRenegotiation(HandshakeStatus handshakeStatus) { synchronized (handshakeLock) { if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING || handshakeStatus == HandshakeStatus.FINISHED) { // Not handshaking return; } if (!handshaken) { // Not renegotiation return; } final boolean renegotiate; if (handshaking) { // Renegotiation in progress or failed already. // i.e. Renegotiation check has been done already below. return; } if (engine.isInboundDone() || engine.isOutboundDone()) { // Not handshaking but closing. return; } if (isEnableRenegotiation()) { // Continue renegotiation. renegotiate = true; } else { // Do not renegotiate. renegotiate = false; // Prevent reentrance of this method. handshaking = true; } if (renegotiate) { // Renegotiate. handshake(); } else { // Raise an exception. fireExceptionCaught( ctx, new SSLException( "renegotiation attempted by peer; " + "closing the connection")); // Close the connection to stop renegotiation. Channels.close(ctx, succeededFuture(ctx.getChannel())); } } } private void runDelegatedTasks() { for (;;) { final Runnable task; synchronized (handshakeLock) { task = engine.getDelegatedTask(); } if (task == null) { break; } delegatedTaskExecutor.execute(new Runnable() { public void run() { synchronized (handshakeLock) { task.run(); } } }); } } private void setHandshakeSuccess(Channel channel) { synchronized (handshakeLock) { handshaking = false; handshaken = true; if (handshakeFuture == null) { handshakeFuture = future(channel); } cancelHandshakeTimeout(); } handshakeFuture.setSuccess(); } private void setHandshakeFailure(Channel channel, SSLException cause) { synchronized (handshakeLock) { if (!handshaking) { return; } handshaking = false; handshaken = false; if (handshakeFuture == null) { handshakeFuture = future(channel); } // cancel the timeout now cancelHandshakeTimeout(); // Release all resources such as internal buffers that SSLEngine // is managing. engine.closeOutbound(); try { engine.closeInbound(); } catch (SSLException e) { if (logger.isDebugEnabled()) { logger.debug( "SSLEngine.closeInbound() raised an exception after " + "a handshake failure.", e); } } } handshakeFuture.setFailure(cause); if (closeOnSSLException) { Channels.close(ctx, future(channel)); } } private void closeOutboundAndChannel( final ChannelHandlerContext context, final ChannelStateEvent e) { if (!e.getChannel().isConnected()) { context.sendDownstream(e); return; } // Ensure that the tear-down logic beyond this point is never invoked concurrently nor multiple times. if (!CLOSED_OUTBOUND_AND_CHANNEL_UPDATER.compareAndSet(this, 0, 1)) { // The other thread called this method already, and thus the connection will be closed eventually. // So, just wait until the connection is closed, and then forward the event so that the sink handles // the duplicate close attempt. e.getChannel().getCloseFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { context.sendDownstream(e); } }); return; } boolean passthrough = true; try { try { unwrap(context, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0); } catch (SSLException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to unwrap before sending a close_notify message", ex); } } if (!engine.isOutboundDone()) { if (SENT_CLOSE_NOTIFY_UPDATER.compareAndSet(this, 0, 1)) { engine.closeOutbound(); try { ChannelFuture closeNotifyFuture = wrapNonAppData(context, e.getChannel()); closeNotifyFuture.addListener( new ClosingChannelFutureListener(context, e)); passthrough = false; } catch (SSLException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to encode a close_notify message", ex); } } } } } finally { if (passthrough) { context.sendDownstream(e); } } } private static final class PendingWrite { final ChannelFuture future; final ByteBuffer outAppBuf; PendingWrite(ChannelFuture future, ByteBuffer outAppBuf) { this.future = future; this.outAppBuf = outAppBuf; } } private static final class ClosingChannelFutureListener implements ChannelFutureListener { private final ChannelHandlerContext context; private final ChannelStateEvent e; ClosingChannelFutureListener( ChannelHandlerContext context, ChannelStateEvent e) { this.context = context; this.e = e; } public void operationComplete(ChannelFuture closeNotifyFuture) throws Exception { if (!(closeNotifyFuture.getCause() instanceof ClosedChannelException)) { Channels.close(context, e.getFuture()); } else { e.getFuture().setSuccess(); } } } @Override public void beforeAdd(ChannelHandlerContext ctx) throws Exception { super.beforeAdd(ctx); this.ctx = ctx; } /** * Fail all pending writes which we were not able to flush out */ @Override public void afterRemove(ChannelHandlerContext ctx) throws Exception { // there is no need for synchronization here as we do not receive downstream events anymore Throwable cause = null; for (;;) { PendingWrite pw = pendingUnencryptedWrites.poll(); if (pw == null) { break; } if (cause == null) { cause = new IOException("Unable to write data"); } pw.future.setFailure(cause); } for (;;) { MessageEvent ev = pendingEncryptedWrites.poll(); if (ev == null) { break; } if (cause == null) { cause = new IOException("Unable to write data"); } ev.getFuture().setFailure(cause); } if (cause != null) { fireExceptionCaughtLater(ctx, cause); } } /** * Calls {@link #handshake()} once the {@link Channel} is connected */ @Override public void channelConnected(final ChannelHandlerContext ctx, final ChannelStateEvent e) throws Exception { if (issueHandshake) { // issue and handshake and add a listener to it which will fire an exception event if // an exception was thrown while doing the handshake handshake().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { // Send the event upstream after the handshake was completed without an error. // // See https://github.com/netty/netty/issues/358 ctx.sendUpstream(e); } } }); } else { super.channelConnected(ctx, e); } } /** * Loop over all the pending writes and fail them. * * See #305 for more details. */ @Override public void channelClosed(final ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Move the fail of the writes to the IO-Thread to prevent possible deadlock // See https://github.com/netty/netty/issues/989 ctx.getPipeline().execute(new Runnable() { public void run() { if (!pendingUnencryptedWritesLock.tryLock()) { return; } Throwable cause = null; try { for (;;) { PendingWrite pw = pendingUnencryptedWrites.poll(); if (pw == null) { break; } if (cause == null) { cause = new ClosedChannelException(); } pw.future.setFailure(cause); } for (;;) { MessageEvent ev = pendingEncryptedWrites.poll(); if (ev == null) { break; } if (cause == null) { cause = new ClosedChannelException(); } ev.getFuture().setFailure(cause); } } finally { pendingUnencryptedWritesLock.unlock(); } if (cause != null) { fireExceptionCaught(ctx, cause); } } }); super.channelClosed(ctx, e); } private final class SSLEngineInboundCloseFuture extends DefaultChannelFuture { public SSLEngineInboundCloseFuture() { super(null, true); } void setClosed() { super.setSuccess(); } @Override public Channel getChannel() { if (ctx == null) { // Maybe we should better throw an IllegalStateException() ? return null; } else { return ctx.getChannel(); } } @Override public boolean setSuccess() { return false; } @Override public boolean setFailure(Throwable cause) { return false; } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/ssl/package-info.java000066400000000000000000000015461225554127700302120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * SSL · * TLS implementation based on {@link javax.net.ssl.SSLEngine} * * @apiviz.exclude \.(channel|codec)\. */ package org.jboss.netty.handler.ssl; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/000077500000000000000000000000001225554127700255075ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/ChunkedFile.java000066400000000000000000000113371225554127700305400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import static org.jboss.netty.buffer.ChannelBuffers.*; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import org.jboss.netty.channel.FileRegion; /** * A {@link ChunkedInput} that fetches data from a file chunk by chunk. *

* If your operating system supports * zero-copy file transfer * such as {@code sendfile()}, you might want to use {@link FileRegion} instead. */ public class ChunkedFile implements ChunkedInput { private final RandomAccessFile file; private final long startOffset; private final long endOffset; private final int chunkSize; private long offset; /** * Creates a new instance that fetches data from the specified file. */ public ChunkedFile(File file) throws IOException { this(file, ChunkedStream.DEFAULT_CHUNK_SIZE); } /** * Creates a new instance that fetches data from the specified file. * * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedFile(File file, int chunkSize) throws IOException { this(new RandomAccessFile(file, "r"), chunkSize); } /** * Creates a new instance that fetches data from the specified file. */ public ChunkedFile(RandomAccessFile file) throws IOException { this(file, ChunkedStream.DEFAULT_CHUNK_SIZE); } /** * Creates a new instance that fetches data from the specified file. * * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedFile(RandomAccessFile file, int chunkSize) throws IOException { this(file, 0, file.length(), chunkSize); } /** * Creates a new instance that fetches data from the specified file. * * @param offset the offset of the file where the transfer begins * @param length the number of bytes to transfer * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedFile(RandomAccessFile file, long offset, long length, int chunkSize) throws IOException { if (file == null) { throw new NullPointerException("file"); } if (offset < 0) { throw new IllegalArgumentException( "offset: " + offset + " (expected: 0 or greater)"); } if (length < 0) { throw new IllegalArgumentException( "length: " + length + " (expected: 0 or greater)"); } if (chunkSize <= 0) { throw new IllegalArgumentException( "chunkSize: " + chunkSize + " (expected: a positive integer)"); } this.file = file; this.offset = startOffset = offset; endOffset = offset + length; this.chunkSize = chunkSize; file.seek(offset); } /** * Returns the offset in the file where the transfer began. */ public long getStartOffset() { return startOffset; } /** * Returns the offset in the file where the transfer will end. */ public long getEndOffset() { return endOffset; } /** * Returns the offset in the file where the transfer is happening currently. */ public long getCurrentOffset() { return offset; } public boolean hasNextChunk() throws Exception { return offset < endOffset && file.getChannel().isOpen(); } public boolean isEndOfInput() throws Exception { return !hasNextChunk(); } public void close() throws Exception { file.close(); } public Object nextChunk() throws Exception { long offset = this.offset; if (offset >= endOffset) { return null; } int chunkSize = (int) Math.min(this.chunkSize, endOffset - offset); byte[] chunk = new byte[chunkSize]; file.readFully(chunk); this.offset = offset + chunkSize; return wrappedBuffer(chunk); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/ChunkedInput.java000066400000000000000000000044771225554127700307670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import org.jboss.netty.buffer.ChannelBuffer; /** * A data stream of indefinite length which is consumed by {@link ChunkedWriteHandler}. * @apiviz.landmark */ public interface ChunkedInput { /** * Returns {@code true} if and only if there is any data left in the * stream. Please note that {@code false} does not necessarily mean that * the stream has reached at its end. In a slow stream, the next chunk * might be unavailable just momentarily. */ boolean hasNextChunk() throws Exception; /** * Fetches a chunked data from the stream. The returned chunk is usually * a {@link ChannelBuffer}, but you could extend an existing implementation * to convert the {@link ChannelBuffer} into a different type that your * handler or encoder understands. Once this method returns the last chunk * and thus the stream has reached at its end, any subsequent {@link #isEndOfInput()} * call must return {@code false}. * * @return the fetched chunk, which is usually {@link ChannelBuffer}. * {@code null} if there is no data left in the stream. * Please note that {@code null} does not necessarily mean that the * stream has reached at its end. In a slow stream, the next chunk * might be unavailable just momentarily. */ Object nextChunk() throws Exception; /** * Return {@code true} if and only if there is no data left in the stream * and the stream has reached at its end. */ boolean isEndOfInput() throws Exception; /** * Releases the resources associated with the stream. */ void close() throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/ChunkedNioFile.java000066400000000000000000000122231225554127700312010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import org.jboss.netty.channel.FileRegion; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import static org.jboss.netty.buffer.ChannelBuffers.*; /** * A {@link ChunkedInput} that fetches data from a file chunk by chunk using * NIO {@link FileChannel}. *

* If your operating system supports * zero-copy file transfer * such as {@code sendfile()}, you might want to use {@link FileRegion} instead. */ public class ChunkedNioFile implements ChunkedInput { private final FileChannel in; private final long startOffset; private final long endOffset; private final int chunkSize; private long offset; /** * Creates a new instance that fetches data from the specified file. */ public ChunkedNioFile(File in) throws IOException { this(new FileInputStream(in).getChannel()); } /** * Creates a new instance that fetches data from the specified file. * * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedNioFile(File in, int chunkSize) throws IOException { this(new FileInputStream(in).getChannel(), chunkSize); } /** * Creates a new instance that fetches data from the specified file. */ public ChunkedNioFile(FileChannel in) throws IOException { this(in, ChunkedStream.DEFAULT_CHUNK_SIZE); } /** * Creates a new instance that fetches data from the specified file. * * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedNioFile(FileChannel in, int chunkSize) throws IOException { this(in, 0, in.size(), chunkSize); } /** * Creates a new instance that fetches data from the specified file. * * @param offset the offset of the file where the transfer begins * @param length the number of bytes to transfer * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedNioFile(FileChannel in, long offset, long length, int chunkSize) throws IOException { if (in == null) { throw new NullPointerException("in"); } if (offset < 0) { throw new IllegalArgumentException( "offset: " + offset + " (expected: 0 or greater)"); } if (length < 0) { throw new IllegalArgumentException( "length: " + length + " (expected: 0 or greater)"); } if (chunkSize <= 0) { throw new IllegalArgumentException( "chunkSize: " + chunkSize + " (expected: a positive integer)"); } if (offset != 0) { in.position(offset); } this.in = in; this.chunkSize = chunkSize; this.offset = startOffset = offset; endOffset = offset + length; } /** * Returns the offset in the file where the transfer began. */ public long getStartOffset() { return startOffset; } /** * Returns the offset in the file where the transfer will end. */ public long getEndOffset() { return endOffset; } /** * Returns the offset in the file where the transfer is happening currently. */ public long getCurrentOffset() { return offset; } public boolean hasNextChunk() throws Exception { return offset < endOffset && in.isOpen(); } public boolean isEndOfInput() throws Exception { return !hasNextChunk(); } public void close() throws Exception { in.close(); } public Object nextChunk() throws Exception { long offset = this.offset; if (offset >= endOffset) { return null; } int chunkSize = (int) Math.min(this.chunkSize, endOffset - offset); byte[] chunkArray = new byte[chunkSize]; ByteBuffer chunk = ByteBuffer.wrap(chunkArray); int readBytes = 0; for (;;) { int localReadBytes = in.read(chunk); if (localReadBytes < 0) { break; } readBytes += localReadBytes; if (readBytes == chunkSize) { break; } } this.offset += readBytes; return wrappedBuffer(chunkArray); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/ChunkedNioStream.java000066400000000000000000000073121225554127700315600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import static org.jboss.netty.buffer.ChannelBuffers.*; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import org.jboss.netty.buffer.ChannelBuffer; /** * A {@link ChunkedInput} that fetches data from a {@link ReadableByteChannel} * chunk by chunk. Please note that the {@link ReadableByteChannel} must * operate in blocking mode. Non-blocking mode channels are not supported. */ public class ChunkedNioStream implements ChunkedInput { private final ReadableByteChannel in; private final int chunkSize; private long offset; /** * Associated ByteBuffer */ private final ByteBuffer byteBuffer; /** * Creates a new instance that fetches data from the specified channel. */ public ChunkedNioStream(ReadableByteChannel in) { this(in, ChunkedStream.DEFAULT_CHUNK_SIZE); } /** * Creates a new instance that fetches data from the specified channel. * * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedNioStream(ReadableByteChannel in, int chunkSize) { if (in == null) { throw new NullPointerException("in"); } if (chunkSize <= 0) { throw new IllegalArgumentException("chunkSize: " + chunkSize + " (expected: a positive integer)"); } this.in = in; offset = 0; this.chunkSize = chunkSize; byteBuffer = ByteBuffer.allocate(chunkSize); } /** * Returns the number of transferred bytes. */ public long getTransferredBytes() { return offset; } public boolean hasNextChunk() throws Exception { if (byteBuffer.position() > 0) { // A previous read was not over, so there is a next chunk in the buffer at least return true; } if (in.isOpen()) { // Try to read a new part, and keep this part (no rewind) int b = in.read(byteBuffer); if (b < 0) { return false; } else { offset += b; return true; } } return false; } public boolean isEndOfInput() throws Exception { return !hasNextChunk(); } public void close() throws Exception { in.close(); } public Object nextChunk() throws Exception { if (!hasNextChunk()) { return null; } // buffer cannot be not be empty from there int readBytes = byteBuffer.position(); for (;;) { int localReadBytes = in.read(byteBuffer); if (localReadBytes < 0) { break; } readBytes += localReadBytes; offset += localReadBytes; if (readBytes == chunkSize) { break; } } byteBuffer.flip(); // copy since buffer is keeped for next usage ChannelBuffer buffer = copiedBuffer(byteBuffer); byteBuffer.clear(); return buffer; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/ChunkedStream.java000066400000000000000000000072241225554127700311140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import static org.jboss.netty.buffer.ChannelBuffers.*; import java.io.InputStream; import java.io.PushbackInputStream; /** * A {@link ChunkedInput} that fetches data from an {@link InputStream} chunk by * chunk. *

* Please note that the {@link InputStream} instance that feeds data into * {@link ChunkedStream} must implement {@link InputStream#available()} as * accurately as possible, rather than using the default implementation. * Otherwise, {@link ChunkedStream} will generate many too small chunks or * block unnecessarily often. */ public class ChunkedStream implements ChunkedInput { static final int DEFAULT_CHUNK_SIZE = 8192; private final PushbackInputStream in; private final int chunkSize; private long offset; /** * Creates a new instance that fetches data from the specified stream. */ public ChunkedStream(InputStream in) { this(in, DEFAULT_CHUNK_SIZE); } /** * Creates a new instance that fetches data from the specified stream. * * @param chunkSize the number of bytes to fetch on each * {@link #nextChunk()} call */ public ChunkedStream(InputStream in, int chunkSize) { if (in == null) { throw new NullPointerException("in"); } if (chunkSize <= 0) { throw new IllegalArgumentException( "chunkSize: " + chunkSize + " (expected: a positive integer)"); } if (in instanceof PushbackInputStream) { this.in = (PushbackInputStream) in; } else { this.in = new PushbackInputStream(in); } this.chunkSize = chunkSize; } /** * Returns the number of transferred bytes. */ public long getTransferredBytes() { return offset; } public boolean hasNextChunk() throws Exception { int b = in.read(); if (b < 0) { return false; } else { in.unread(b); return true; } } public boolean isEndOfInput() throws Exception { return !hasNextChunk(); } public void close() throws Exception { in.close(); } public Object nextChunk() throws Exception { if (!hasNextChunk()) { return null; } final int availableBytes = in.available(); final int chunkSize; if (availableBytes <= 0) { chunkSize = this.chunkSize; } else { chunkSize = Math.min(this.chunkSize, in.available()); } final byte[] chunk = new byte[chunkSize]; int readBytes = 0; for (;;) { int localReadBytes = in.read(chunk, readBytes, chunkSize - readBytes); if (localReadBytes < 0) { break; } readBytes += localReadBytes; offset += localReadBytes; if (readBytes == chunkSize) { break; } } return wrappedBuffer(chunk, 0, readBytes); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/ChunkedWriteHandler.java000066400000000000000000000335171225554127700322550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import static org.jboss.netty.channel.Channels.*; /** * A {@link ChannelHandler} that adds support for writing a large data stream * asynchronously neither spending a lot of memory nor getting * {@link OutOfMemoryError}. Large data streaming such as file * transfer requires complicated state management in a {@link ChannelHandler} * implementation. {@link ChunkedWriteHandler} manages such complicated states * so that you can send a large data stream without difficulties. *

* To use {@link ChunkedWriteHandler} in your application, you have to insert * a new {@link ChunkedWriteHandler} instance: *

 * {@link ChannelPipeline} p = ...;
 * p.addLast("streamer", new {@link ChunkedWriteHandler}());
 * p.addLast("handler", new MyHandler());
 * 
* Once inserted, you can write a {@link ChunkedInput} so that the * {@link ChunkedWriteHandler} can pick it up and fetch the content of the * stream chunk by chunk and write the fetched chunk downstream: *
 * {@link Channel} ch = ...;
 * ch.write(new {@link ChunkedFile}(new File("video.mkv"));
 * 
* *

Sending a stream which generates a chunk intermittently

* * Some {@link ChunkedInput} generates a chunk on a certain event or timing. * Such {@link ChunkedInput} implementation often returns {@code null} on * {@link ChunkedInput#nextChunk()}, resulting in the indefinitely suspended * transfer. To resume the transfer when a new chunk is available, you have to * call {@link #resumeTransfer()}. * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.stream.ChunkedInput oneway - - reads from */ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler, LifeCycleAwareChannelHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChunkedWriteHandler.class); private final Queue queue = new ConcurrentLinkedQueue(); private volatile ChannelHandlerContext ctx; private final AtomicBoolean flush = new AtomicBoolean(false); private MessageEvent currentEvent; private volatile boolean flushNeeded; /** * Continues to fetch the chunks from the input. */ public void resumeTransfer() { ChannelHandlerContext ctx = this.ctx; if (ctx == null) { return; } try { flush(ctx, false); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn("Unexpected exception while sending chunks.", e); } } } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (!(e instanceof MessageEvent)) { ctx.sendDownstream(e); return; } boolean offered = queue.offer((MessageEvent) e); assert offered; final Channel channel = ctx.getChannel(); // call flush if the channel is writable or not connected. flush(..) will take care of the rest if (channel.isWritable() || !channel.isConnected()) { this.ctx = ctx; flush(ctx, false); } } public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { ChannelStateEvent cse = (ChannelStateEvent) e; switch (cse.getState()) { case INTEREST_OPS: // Continue writing when the channel becomes writable. flush(ctx, true); break; case OPEN: if (!Boolean.TRUE.equals(cse.getValue())) { // Fail all pending writes flush(ctx, true); } break; } } ctx.sendUpstream(e); } private void discard(ChannelHandlerContext ctx, boolean fireNow) { ClosedChannelException cause = null; for (;;) { MessageEvent currentEvent = this.currentEvent; if (this.currentEvent == null) { currentEvent = queue.poll(); } else { this.currentEvent = null; } if (currentEvent == null) { break; } Object m = currentEvent.getMessage(); if (m instanceof ChunkedInput) { closeInput((ChunkedInput) m); } // Trigger a ClosedChannelException if (cause == null) { cause = new ClosedChannelException(); } currentEvent.getFuture().setFailure(cause); } if (cause != null) { if (fireNow) { fireExceptionCaught(ctx.getChannel(), cause); } else { fireExceptionCaughtLater(ctx.getChannel(), cause); } } } private void flush(ChannelHandlerContext ctx, boolean fireNow) throws Exception { boolean acquired; final Channel channel = ctx.getChannel(); boolean suspend = false; flushNeeded = true; // use CAS to see if the have flush already running, if so we don't need to take futher actions if (acquired = flush.compareAndSet(false, true)) { flushNeeded = false; try { if (!channel.isConnected()) { discard(ctx, fireNow); return; } while (channel.isWritable()) { if (currentEvent == null) { currentEvent = queue.poll(); } if (currentEvent == null) { break; } if (currentEvent.getFuture().isDone()) { // Skip the current request because the previous partial write // attempt for the current request has been failed. currentEvent = null; } else { final MessageEvent currentEvent = this.currentEvent; Object m = currentEvent.getMessage(); if (m instanceof ChunkedInput) { final ChunkedInput chunks = (ChunkedInput) m; Object chunk; boolean endOfInput; try { chunk = chunks.nextChunk(); endOfInput = chunks.isEndOfInput(); if (chunk == null) { chunk = ChannelBuffers.EMPTY_BUFFER; // No need to suspend when reached at the end. suspend = !endOfInput; } else { suspend = false; } } catch (Throwable t) { this.currentEvent = null; currentEvent.getFuture().setFailure(t); if (fireNow) { fireExceptionCaught(ctx, t); } else { fireExceptionCaughtLater(ctx, t); } closeInput(chunks); break; } if (suspend) { // ChunkedInput.nextChunk() returned null and it has // not reached at the end of input. Let's wait until // more chunks arrive. Nothing to write or notify. break; } else { ChannelFuture writeFuture; if (endOfInput) { this.currentEvent = null; writeFuture = currentEvent.getFuture(); // Register a listener which will close the input once the write // is complete. This is needed because the Chunk may have some // resource bound that can not be closed before its not written // // See https://github.com/netty/netty/issues/303 writeFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { closeInput(chunks); } }); } else { writeFuture = future(channel); writeFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { currentEvent.getFuture().setFailure(future.getCause()); closeInput((ChunkedInput) currentEvent.getMessage()); } } }); } write( ctx, writeFuture, chunk, currentEvent.getRemoteAddress()); } } else { this.currentEvent = null; ctx.sendDownstream(currentEvent); } } if (!channel.isConnected()) { discard(ctx, fireNow); return; } } } finally { // mark the flush as done flush.set(false); } } if (acquired && (!channel.isConnected() || channel.isWritable() && !queue.isEmpty() && !suspend || flushNeeded)) { flush(ctx, fireNow); } } static void closeInput(ChunkedInput chunks) { try { chunks.close(); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("Failed to close a chunked input.", t); } } } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { // nothing to do } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // nothing to do } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { // try to flush again a last time. // // See #304 flush(ctx, false); } // This method should not need any synchronization as the ChunkedWriteHandler will not receive any new events public void afterRemove(ChannelHandlerContext ctx) throws Exception { // Fail all MessageEvent's that are left. This is needed because otherwise we would never notify the // ChannelFuture and the registered FutureListener. See #304 Throwable cause = null; boolean fireExceptionCaught = false; for (;;) { MessageEvent currentEvent = this.currentEvent; if (this.currentEvent == null) { currentEvent = queue.poll(); } else { this.currentEvent = null; } if (currentEvent == null) { break; } Object m = currentEvent.getMessage(); if (m instanceof ChunkedInput) { closeInput((ChunkedInput) m); } // Create exception if (cause == null) { cause = new IOException("Unable to flush event, discarding"); } currentEvent.getFuture().setFailure(cause); fireExceptionCaught = true; } if (fireExceptionCaught) { fireExceptionCaughtLater(ctx.getChannel(), cause); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/stream/package-info.java000066400000000000000000000016511225554127700307010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Writes very large data stream asynchronously neither spending a lot of * memory nor getting {@link java.lang.OutOfMemoryError}. For a detailed * example, please refer to {@code org.jboss.netty.example.http.file}. * * @apiviz.exclude \.channel\. */ package org.jboss.netty.handler.stream; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/000077500000000000000000000000001225554127700257025ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/DefaultIdleStateEvent.java000066400000000000000000000043051225554127700327340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import static org.jboss.netty.channel.Channels.*; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; /** * The default {@link IdleStateEvent} implementation. */ public class DefaultIdleStateEvent implements IdleStateEvent { private final Channel channel; private final IdleState state; private final long lastActivityTimeMillis; /** * Creates a new instance. */ public DefaultIdleStateEvent( Channel channel, IdleState state, long lastActivityTimeMillis) { if (channel == null) { throw new NullPointerException("channel"); } if (state == null) { throw new NullPointerException("state"); } this.channel = channel; this.state = state; this.lastActivityTimeMillis = lastActivityTimeMillis; } public Channel getChannel() { return channel; } public ChannelFuture getFuture() { return succeededFuture(getChannel()); } public IdleState getState() { return state; } public long getLastActivityTimeMillis() { return lastActivityTimeMillis; } @Override public String toString() { return getChannel().toString() + ' ' + getState() + " since " + DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, Locale.US).format( new Date(getLastActivityTimeMillis())); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/IdleState.java000066400000000000000000000020361225554127700304240ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.channel.Channel; /** * An {@link Enum} that represents the idle state of a {@link Channel}. */ public enum IdleState { /** * No data was received for a while. */ READER_IDLE, /** * No data was sent for a while. */ WRITER_IDLE, /** * No data was either received or sent for a while. */ ALL_IDLE } IdleStateAwareChannelHandler.java000066400000000000000000000031241225554127700341130ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.SimpleChannelHandler; /** * An extended {@link SimpleChannelHandler} that adds the handler method for * an {@link IdleStateEvent}. * @apiviz.uses org.jboss.netty.handler.timeout.IdleStateEvent */ public class IdleStateAwareChannelHandler extends SimpleChannelHandler { @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof IdleStateEvent) { channelIdle(ctx, (IdleStateEvent) e); } else { super.handleUpstream(ctx, e); } } /** * Invoked when a {@link Channel} has been idle for a while. */ public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception { ctx.sendUpstream(e); } } IdleStateAwareChannelUpstreamHandler.java000066400000000000000000000031641225554127700356400ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * An extended {@link SimpleChannelUpstreamHandler} that adds the handler method * for an {@link IdleStateEvent}. * @apiviz.uses org.jboss.netty.handler.timeout.IdleStateEvent */ public class IdleStateAwareChannelUpstreamHandler extends SimpleChannelUpstreamHandler { @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof IdleStateEvent) { channelIdle(ctx, (IdleStateEvent) e); } else { super.handleUpstream(ctx, e); } } /** * Invoked when a {@link Channel} has been idle for a while. */ public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception { ctx.sendUpstream(e); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/IdleStateEvent.java000066400000000000000000000022761225554127700314340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; /** * A {@link ChannelEvent} that is triggered when a {@link Channel} has been idle * for a while. * @apiviz.landmark * @apiviz.has org.jboss.netty.handler.timeout.IdleState oneway - - */ public interface IdleStateEvent extends ChannelEvent { /** * Returns the detailed idle state. */ IdleState getState(); /** * Returns the last time when I/O occurred in milliseconds. */ long getLastActivityTimeMillis(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/IdleStateHandler.java000066400000000000000000000435551225554127700317350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import static org.jboss.netty.channel.Channels.*; import java.util.concurrent.TimeUnit; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.WriteCompletionEvent; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; /** * Triggers an {@link IdleStateEvent} when a {@link Channel} has not performed * read, write, or both operation for a while. * *

Supported idle states

* * * * * * * * * * * * * * * * *
PropertyMeaning
{@code readerIdleTime}an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified period of * time. Specify {@code 0} to disable.
{@code writerIdleTime}an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified period of * time. Specify {@code 0} to disable.
{@code allIdleTime}an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for the * specified period of time. Specify {@code 0} to disable.
* *
 * // An example that sends a ping message when there is no outbound traffic
 * // for 30 seconds.  The connection is closed when there is no inbound traffic
 * // for 60 seconds.
 *
 * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private final {@link Timer} timer;
 *     private final {@link ChannelHandler} idleStateHandler;
 *
 *     public MyPipelineFactory({@link Timer} timer) {
 *         this.timer = timer;
 *         this.idleStateHandler = new {@link IdleStateHandler}(timer, 60, 30, 0), // timer must be shared.
 *     }
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(
 *             idleStateHandler,
 *             new MyHandler());
 *     }
 * }
 *
 * // Handler should handle the {@link IdleStateEvent} triggered by {@link IdleStateHandler}.
 * public class MyHandler extends {@link IdleStateAwareChannelHandler} {
 *
 *     {@code @Override}
 *     public void channelIdle({@link ChannelHandlerContext} ctx, {@link IdleStateEvent} e) {
 *         if (e.getState() == {@link IdleState}.READER_IDLE) {
 *             e.getChannel().close();
 *         } else if (e.getState() == {@link IdleState}.WRITER_IDLE) {
 *             e.getChannel().write(new PingMessage());
 *         }
 *     }
 * }
 *
 * {@link ServerBootstrap} bootstrap = ...;
 * {@link Timer} timer = new {@link HashedWheelTimer}();
 * ...
 * bootstrap.setPipelineFactory(new MyPipelineFactory(timer));
 * ...
 * 
* * The {@link Timer} which was specified when the {@link IdleStateHandler} is * created should be stopped manually by calling {@link #releaseExternalResources()} * or {@link Timer#stop()} when your application shuts down. * @see ReadTimeoutHandler * @see WriteTimeoutHandler * * @apiviz.landmark * @apiviz.uses org.jboss.netty.util.HashedWheelTimer * @apiviz.has org.jboss.netty.handler.timeout.IdleStateEvent oneway - - triggers */ @Sharable public class IdleStateHandler extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler, ExternalResourceReleasable { final Timer timer; final long readerIdleTimeMillis; final long writerIdleTimeMillis; final long allIdleTimeMillis; /** * Creates a new instance. * * @param timer * the {@link Timer} that is used to trigger the scheduled event. * The recommended {@link Timer} implementation is {@link HashedWheelTimer}. * @param readerIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified * period of time. Specify {@code 0} to disable. * @param writerIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified * period of time. Specify {@code 0} to disable. * @param allIdleTimeSeconds * an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for * the specified period of time. Specify {@code 0} to disable. */ public IdleStateHandler( Timer timer, int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) { this(timer, readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds, TimeUnit.SECONDS); } /** * Creates a new instance. * * @param timer * the {@link Timer} that is used to trigger the scheduled event. * The recommended {@link Timer} implementation is {@link HashedWheelTimer}. * @param readerIdleTime * an {@link IdleStateEvent} whose state is {@link IdleState#READER_IDLE} * will be triggered when no read was performed for the specified * period of time. Specify {@code 0} to disable. * @param writerIdleTime * an {@link IdleStateEvent} whose state is {@link IdleState#WRITER_IDLE} * will be triggered when no write was performed for the specified * period of time. Specify {@code 0} to disable. * @param allIdleTime * an {@link IdleStateEvent} whose state is {@link IdleState#ALL_IDLE} * will be triggered when neither read nor write was performed for * the specified period of time. Specify {@code 0} to disable. * @param unit * the {@link TimeUnit} of {@code readerIdleTime}, * {@code writeIdleTime}, and {@code allIdleTime} */ public IdleStateHandler( Timer timer, long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit) { if (timer == null) { throw new NullPointerException("timer"); } if (unit == null) { throw new NullPointerException("unit"); } this.timer = timer; if (readerIdleTime <= 0) { readerIdleTimeMillis = 0; } else { readerIdleTimeMillis = Math.max(unit.toMillis(readerIdleTime), 1); } if (writerIdleTime <= 0) { writerIdleTimeMillis = 0; } else { writerIdleTimeMillis = Math.max(unit.toMillis(writerIdleTime), 1); } if (allIdleTime <= 0) { allIdleTimeMillis = 0; } else { allIdleTimeMillis = Math.max(unit.toMillis(allIdleTime), 1); } } /** * Return the readerIdleTime that was given when instance this class in milliseconds. * */ public long getReaderIdleTimeInMillis() { return readerIdleTimeMillis; } /** * Return the writerIdleTime that was given when instance this class in milliseconds. * */ public long getWriterIdleTimeInMillis() { return writerIdleTimeMillis; } /** * Return the allIdleTime that was given when instance this class in milliseconds. * */ public long getAllIdleTimeInMillis() { return allIdleTimeMillis; } /** * Stops the {@link Timer} which was specified in the constructor of this * handler. You should not call this method if the {@link Timer} is in use * by other objects. */ public void releaseExternalResources() { timer.stop(); } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { if (ctx.getPipeline().isAttached()) { // channelOpen event has been fired already, which means // this.channelOpen() will not be invoked. // We have to initialize here instead. initialize(ctx); } else { // channelOpen event has not been fired yet. // this.channelOpen() will be invoked and initialization will occur there. } } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // NOOP } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { destroy(ctx); } public void afterRemove(ChannelHandlerContext ctx) throws Exception { // NOOP } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // This method will be invoked only if this handler was added // before channelOpen event is fired. If a user adds this handler // after the channelOpen event, initialize() will be called by beforeAdd(). initialize(ctx); ctx.sendUpstream(e); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { destroy(ctx); ctx.sendUpstream(e); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { State state = (State) ctx.getAttachment(); state.lastReadTime = System.currentTimeMillis(); ctx.sendUpstream(e); } @Override public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception { if (e.getWrittenAmount() > 0) { State state = (State) ctx.getAttachment(); state.lastWriteTime = System.currentTimeMillis(); } ctx.sendUpstream(e); } private void initialize(ChannelHandlerContext ctx) { State state = state(ctx); // Avoid the case where destroy() is called before scheduling timeouts. // See: https://github.com/netty/netty/issues/143 synchronized (state) { switch (state.state) { case 1: case 2: return; } state.state = 1; } state.lastReadTime = state.lastWriteTime = System.currentTimeMillis(); if (readerIdleTimeMillis > 0) { state.readerIdleTimeout = timer.newTimeout( new ReaderIdleTimeoutTask(ctx), readerIdleTimeMillis, TimeUnit.MILLISECONDS); } if (writerIdleTimeMillis > 0) { state.writerIdleTimeout = timer.newTimeout( new WriterIdleTimeoutTask(ctx), writerIdleTimeMillis, TimeUnit.MILLISECONDS); } if (allIdleTimeMillis > 0) { state.allIdleTimeout = timer.newTimeout( new AllIdleTimeoutTask(ctx), allIdleTimeMillis, TimeUnit.MILLISECONDS); } } private static void destroy(ChannelHandlerContext ctx) { State state = state(ctx); synchronized (state) { if (state.state != 1) { return; } state.state = 2; } if (state.readerIdleTimeout != null) { state.readerIdleTimeout.cancel(); state.readerIdleTimeout = null; } if (state.writerIdleTimeout != null) { state.writerIdleTimeout.cancel(); state.writerIdleTimeout = null; } if (state.allIdleTimeout != null) { state.allIdleTimeout.cancel(); state.allIdleTimeout = null; } } private static State state(ChannelHandlerContext ctx) { State state; synchronized (ctx) { // FIXME: It could have been better if there is setAttachmentIfAbsent(). state = (State) ctx.getAttachment(); if (state != null) { return state; } state = new State(); ctx.setAttachment(state); } return state; } private void fireChannelIdle( final ChannelHandlerContext ctx, final IdleState state, final long lastActivityTimeMillis) { ctx.getPipeline().execute(new Runnable() { public void run() { try { channelIdle(ctx, state, lastActivityTimeMillis); } catch (Throwable t) { fireExceptionCaught(ctx, t); } } }); } protected void channelIdle( ChannelHandlerContext ctx, IdleState state, long lastActivityTimeMillis) throws Exception { ctx.sendUpstream(new DefaultIdleStateEvent(ctx.getChannel(), state, lastActivityTimeMillis)); } private final class ReaderIdleTimeoutTask implements TimerTask { private final ChannelHandlerContext ctx; ReaderIdleTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } public void run(Timeout timeout) throws Exception { if (timeout.isCancelled() || !ctx.getChannel().isOpen()) { return; } State state = (State) ctx.getAttachment(); long currentTime = System.currentTimeMillis(); long lastReadTime = state.lastReadTime; long nextDelay = readerIdleTimeMillis - (currentTime - lastReadTime); if (nextDelay <= 0) { // Reader is idle - set a new timeout and notify the callback. state.readerIdleTimeout = timer.newTimeout(this, readerIdleTimeMillis, TimeUnit.MILLISECONDS); fireChannelIdle(ctx, IdleState.READER_IDLE, lastReadTime); } else { // Read occurred before the timeout - set a new timeout with shorter delay. state.readerIdleTimeout = timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); } } } private final class WriterIdleTimeoutTask implements TimerTask { private final ChannelHandlerContext ctx; WriterIdleTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } public void run(Timeout timeout) throws Exception { if (timeout.isCancelled() || !ctx.getChannel().isOpen()) { return; } State state = (State) ctx.getAttachment(); long currentTime = System.currentTimeMillis(); long lastWriteTime = state.lastWriteTime; long nextDelay = writerIdleTimeMillis - (currentTime - lastWriteTime); if (nextDelay <= 0) { // Writer is idle - set a new timeout and notify the callback. state.writerIdleTimeout = timer.newTimeout(this, writerIdleTimeMillis, TimeUnit.MILLISECONDS); fireChannelIdle(ctx, IdleState.WRITER_IDLE, lastWriteTime); } else { // Write occurred before the timeout - set a new timeout with shorter delay. state.writerIdleTimeout = timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); } } } private final class AllIdleTimeoutTask implements TimerTask { private final ChannelHandlerContext ctx; AllIdleTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } public void run(Timeout timeout) throws Exception { if (timeout.isCancelled() || !ctx.getChannel().isOpen()) { return; } State state = (State) ctx.getAttachment(); long currentTime = System.currentTimeMillis(); long lastIoTime = Math.max(state.lastReadTime, state.lastWriteTime); long nextDelay = allIdleTimeMillis - (currentTime - lastIoTime); if (nextDelay <= 0) { // Both reader and writer are idle - set a new timeout and // notify the callback. state.allIdleTimeout = timer.newTimeout(this, allIdleTimeMillis, TimeUnit.MILLISECONDS); fireChannelIdle(ctx, IdleState.ALL_IDLE, lastIoTime); } else { // Either read or write occurred before the timeout - set a new // timeout with shorter delay. state.allIdleTimeout = timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); } } } private static final class State { // 0 - none, 1 - initialized, 2 - destroyed int state; volatile Timeout readerIdleTimeout; volatile long lastReadTime; volatile Timeout writerIdleTimeout; volatile long lastWriteTime; volatile Timeout allIdleTimeout; State() { } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/ReadTimeoutException.java000066400000000000000000000026431225554127700326530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; /** * A {@link TimeoutException} raised by {@link ReadTimeoutHandler} when no data * was read within a certain period of time. */ public class ReadTimeoutException extends TimeoutException { private static final long serialVersionUID = -4596059237992273913L; /** * Creates a new instance. */ public ReadTimeoutException() { } /** * Creates a new instance. */ public ReadTimeoutException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public ReadTimeoutException(String message) { super(message); } /** * Creates a new instance. */ public ReadTimeoutException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/ReadTimeoutHandler.java000066400000000000000000000230551225554127700322720ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.LifeCycleAwareChannelHandler; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import java.util.concurrent.TimeUnit; import static org.jboss.netty.channel.Channels.*; /** * Raises a {@link ReadTimeoutException} when no data was read within a certain * period of time. * *
 * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private final {@link Timer} timer;
 *     private final {@link ChannelHandler} timeoutHandler;
 *
 *     public MyPipelineFactory({@link Timer} timer) {
 *         this.timer = timer;
 *         this.timeoutHandler = new {@link ReadTimeoutHandler}(timer, 30), // timer must be shared.
 *     }
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         // An example configuration that implements 30-second read timeout:
 *         return {@link Channels}.pipeline(
 *             timeoutHandler,
 *             new MyHandler());
 *     }
 * }
 *
 * {@link ServerBootstrap} bootstrap = ...;
 * {@link Timer} timer = new {@link HashedWheelTimer}();
 * ...
 * bootstrap.setPipelineFactory(new MyPipelineFactory(timer));
 * ...
 * 
* * The {@link Timer} which was specified when the {@link ReadTimeoutHandler} is * created should be stopped manually by calling {@link #releaseExternalResources()} * or {@link Timer#stop()} when your application shuts down. * @see WriteTimeoutHandler * @see IdleStateHandler * * @apiviz.landmark * @apiviz.uses org.jboss.netty.util.HashedWheelTimer * @apiviz.has org.jboss.netty.handler.timeout.TimeoutException oneway - - raises */ @Sharable public class ReadTimeoutHandler extends SimpleChannelUpstreamHandler implements LifeCycleAwareChannelHandler, ExternalResourceReleasable { static final ReadTimeoutException EXCEPTION = new ReadTimeoutException(); final Timer timer; final long timeoutMillis; /** * Creates a new instance. * * @param timer * the {@link Timer} that is used to trigger the scheduled event. * The recommended {@link Timer} implementation is {@link HashedWheelTimer}. * @param timeoutSeconds * read timeout in seconds */ public ReadTimeoutHandler(Timer timer, int timeoutSeconds) { this(timer, timeoutSeconds, TimeUnit.SECONDS); } /** * Creates a new instance. * * @param timer * the {@link Timer} that is used to trigger the scheduled event. * The recommended {@link Timer} implementation is {@link HashedWheelTimer}. * @param timeout * read timeout * @param unit * the {@link TimeUnit} of {@code timeout} */ public ReadTimeoutHandler(Timer timer, long timeout, TimeUnit unit) { if (timer == null) { throw new NullPointerException("timer"); } if (unit == null) { throw new NullPointerException("unit"); } this.timer = timer; if (timeout <= 0) { timeoutMillis = 0; } else { timeoutMillis = Math.max(unit.toMillis(timeout), 1); } } /** * Stops the {@link Timer} which was specified in the constructor of this * handler. You should not call this method if the {@link Timer} is in use * by other objects. */ public void releaseExternalResources() { timer.stop(); } public void beforeAdd(ChannelHandlerContext ctx) throws Exception { if (ctx.getPipeline().isAttached()) { // channelOpen event has been fired already, which means // this.channelOpen() will not be invoked. // We have to initialize here instead. initialize(ctx); } else { // channelOpen event has not been fired yet. // this.channelOpen() will be invoked and initialization will occur there. } } public void afterAdd(ChannelHandlerContext ctx) throws Exception { // NOOP } public void beforeRemove(ChannelHandlerContext ctx) throws Exception { destroy(ctx); } public void afterRemove(ChannelHandlerContext ctx) throws Exception { // NOOP } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // This method will be invoked only if this handler was added // before channelOpen event is fired. If a user adds this handler // after the channelOpen event, initialize() will be called by beforeAdd(). initialize(ctx); ctx.sendUpstream(e); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { destroy(ctx); ctx.sendUpstream(e); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { State state = (State) ctx.getAttachment(); state.lastReadTime = System.currentTimeMillis(); ctx.sendUpstream(e); } private void initialize(ChannelHandlerContext ctx) { State state = state(ctx); // Avoid the case where destroy() is called before scheduling timeouts. // See: https://github.com/netty/netty/issues/143 synchronized (state) { switch (state.state) { case 1: case 2: return; } state.state = 1; } if (timeoutMillis > 0) { state.timeout = timer.newTimeout(new ReadTimeoutTask(ctx), timeoutMillis, TimeUnit.MILLISECONDS); } } private static void destroy(ChannelHandlerContext ctx) { State state = state(ctx); synchronized (state) { if (state.state != 1) { return; } state.state = 2; } if (state.timeout != null) { state.timeout.cancel(); state.timeout = null; } } private static State state(ChannelHandlerContext ctx) { State state; synchronized (ctx) { // FIXME: It could have been better if there is setAttachmentIfAbsent(). state = (State) ctx.getAttachment(); if (state != null) { return state; } state = new State(); ctx.setAttachment(state); } return state; } protected void readTimedOut(ChannelHandlerContext ctx) throws Exception { fireExceptionCaught(ctx, EXCEPTION); } private final class ReadTimeoutTask implements TimerTask { private final ChannelHandlerContext ctx; ReadTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } public void run(Timeout timeout) throws Exception { if (timeout.isCancelled()) { return; } if (!ctx.getChannel().isOpen()) { return; } State state = (State) ctx.getAttachment(); long currentTime = System.currentTimeMillis(); long nextDelay = timeoutMillis - (currentTime - state.lastReadTime); if (nextDelay <= 0) { // Read timed out - set a new timeout and notify the callback. state.timeout = timer.newTimeout(this, timeoutMillis, TimeUnit.MILLISECONDS); fireReadTimedOut(ctx); } else { // Read occurred before the timeout - set a new timeout with shorter delay. state.timeout = timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); } } private void fireReadTimedOut(final ChannelHandlerContext ctx) throws Exception { ctx.getPipeline().execute(new Runnable() { public void run() { try { readTimedOut(ctx); } catch (Throwable t) { fireExceptionCaught(ctx, t); } } }); } } private static final class State { // 0 - none, 1 - initialized, 2 - destroyed int state; volatile Timeout timeout; volatile long lastReadTime = System.currentTimeMillis(); State() { } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/TimeoutException.java000066400000000000000000000026551225554127700320620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.channel.ChannelException; /** * A {@link TimeoutException} when no data was either read or written within a * certain period of time. */ public class TimeoutException extends ChannelException { private static final long serialVersionUID = 4673641882869672533L; /** * Creates a new instance. */ public TimeoutException() { } /** * Creates a new instance. */ public TimeoutException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public TimeoutException(String message) { super(message); } /** * Creates a new instance. */ public TimeoutException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/WriteTimeoutException.java000066400000000000000000000026551225554127700330750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; /** * A {@link TimeoutException} raised by {@link WriteTimeoutHandler} when no data * was written within a certain period of time. */ public class WriteTimeoutException extends TimeoutException { private static final long serialVersionUID = -7746685254523245218L; /** * Creates a new instance. */ public WriteTimeoutException() { } /** * Creates a new instance. */ public WriteTimeoutException(String message, Throwable cause) { super(message, cause); } /** * Creates a new instance. */ public WriteTimeoutException(String message) { super(message); } /** * Creates a new instance. */ public WriteTimeoutException(Throwable cause) { super(cause); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/WriteTimeoutHandler.java000066400000000000000000000161471225554127700325150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.timeout; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelDownstreamHandler; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import java.util.concurrent.TimeUnit; import static org.jboss.netty.channel.Channels.*; /** * Raises a {@link WriteTimeoutException} when no data was written within a * certain period of time. * *
 * public class MyPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private final {@link Timer} timer;
 *
 *     public MyPipelineFactory({@link Timer} timer) {
 *         this.timer = timer;
 *     }
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         // An example configuration that implements 30-second write timeout:
 *         return {@link Channels}.pipeline(
 *             new {@link WriteTimeoutHandler}(timer, 30), // timer must be shared.
 *             new MyHandler());
 *     }
 * }
 *
 * {@link ServerBootstrap} bootstrap = ...;
 * {@link Timer} timer = new {@link HashedWheelTimer}();
 * ...
 * bootstrap.setPipelineFactory(new MyPipelineFactory(timer));
 * 
* * The {@link Timer} which was specified when the {@link ReadTimeoutHandler} is * created should be stopped manually by calling {@link #releaseExternalResources()} * or {@link Timer#stop()} when your application shuts down. * @see ReadTimeoutHandler * @see IdleStateHandler * * @apiviz.landmark * @apiviz.uses org.jboss.netty.util.HashedWheelTimer * @apiviz.has org.jboss.netty.handler.timeout.TimeoutException oneway - - raises */ @Sharable public class WriteTimeoutHandler extends SimpleChannelDownstreamHandler implements ExternalResourceReleasable { static final WriteTimeoutException EXCEPTION = new WriteTimeoutException(); private final Timer timer; private final long timeoutMillis; /** * Creates a new instance. * * @param timer * the {@link Timer} that is used to trigger the scheduled event. * The recommended {@link Timer} implementation is {@link HashedWheelTimer}. * @param timeoutSeconds * write timeout in seconds */ public WriteTimeoutHandler(Timer timer, int timeoutSeconds) { this(timer, timeoutSeconds, TimeUnit.SECONDS); } /** * Creates a new instance. * * @param timer * the {@link Timer} that is used to trigger the scheduled event. * The recommended {@link Timer} implementation is {@link HashedWheelTimer}. * @param timeout * write timeout * @param unit * the {@link TimeUnit} of {@code timeout} */ public WriteTimeoutHandler(Timer timer, long timeout, TimeUnit unit) { if (timer == null) { throw new NullPointerException("timer"); } if (unit == null) { throw new NullPointerException("unit"); } this.timer = timer; if (timeout <= 0) { timeoutMillis = 0; } else { timeoutMillis = Math.max(unit.toMillis(timeout), 1); } } /** * Stops the {@link Timer} which was specified in the constructor of this * handler. You should not call this method if the {@link Timer} is in use * by other objects. */ public void releaseExternalResources() { timer.stop(); } /** * Returns the write timeout of the specified event. By default, this method returns the * timeout value you specified in the constructor. Override this method to determine the * timeout value depending on the message being written. * * @param e the message being written */ protected long getTimeoutMillis(MessageEvent e) { return timeoutMillis; } @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { long timeoutMillis = getTimeoutMillis(e); if (timeoutMillis > 0) { // Set timeout only when getTimeoutMillis() returns a positive value. ChannelFuture future = e.getFuture(); final Timeout timeout = timer.newTimeout( new WriteTimeoutTask(ctx, future), timeoutMillis, TimeUnit.MILLISECONDS); future.addListener(new TimeoutCanceller(timeout)); } super.writeRequested(ctx, e); } protected void writeTimedOut(ChannelHandlerContext ctx) throws Exception { fireExceptionCaught(ctx, EXCEPTION); } private final class WriteTimeoutTask implements TimerTask { private final ChannelHandlerContext ctx; private final ChannelFuture future; WriteTimeoutTask(ChannelHandlerContext ctx, ChannelFuture future) { this.ctx = ctx; this.future = future; } public void run(Timeout timeout) throws Exception { if (timeout.isCancelled()) { return; } if (!ctx.getChannel().isOpen()) { return; } // Mark the future as failure if (future.setFailure(EXCEPTION)) { // If succeeded to mark as failure, notify the pipeline, too. fireWriteTimeOut(ctx); } } private void fireWriteTimeOut(final ChannelHandlerContext ctx) { ctx.getPipeline().execute(new Runnable() { public void run() { try { writeTimedOut(ctx); } catch (Throwable t) { fireExceptionCaught(ctx, t); } } }); } } private static final class TimeoutCanceller implements ChannelFutureListener { private final Timeout timeout; TimeoutCanceller(Timeout timeout) { this.timeout = timeout; } public void operationComplete(ChannelFuture future) throws Exception { timeout.cancel(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/timeout/package-info.java000066400000000000000000000016471225554127700311010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Adds support for read and write timeout and idle connection notification * using a {@link org.jboss.netty.util.Timer}. * * @apiviz.exclude \.channel\. * @apiviz.exclude \.DefaultIdleStateEvent$ * @apiviz.exclude \.ExternalResourceReleasable$ */ package org.jboss.netty.handler.timeout; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/traffic/000077500000000000000000000000001225554127700256325ustar00rootroot00000000000000AbstractTrafficShapingHandler.java000066400000000000000000000437741225554127700343070ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/traffic/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.traffic; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.DefaultObjectSizeEstimator; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.ObjectSizeEstimator; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * AbstractTrafficShapingHandler allows to limit the global bandwidth * (see {@link GlobalTrafficShapingHandler}) or per session * bandwidth (see {@link ChannelTrafficShapingHandler}), as traffic shaping. * It allows too to implement an almost real time monitoring of the bandwidth using * the monitors from {@link TrafficCounter} that will call back every checkInterval * the method doAccounting of this handler.
*
* * An {@link ObjectSizeEstimator} can be passed at construction to specify what * is the size of the object to be read or write accordingly to the type of * object. If not specified, it will used the {@link DefaultObjectSizeEstimator} implementation.

* * If you want for any particular reasons to stop the monitoring (accounting) or to change * the read/write limit or the check interval, several methods allow that for you:
*
    *
  • configure allows you to change read or write limits, or the checkInterval
  • *
  • getTrafficCounter allows you to have access to the TrafficCounter and so to stop * or start the monitoring, to change the checkInterval directly, or to have access to its values.
  • *
  • *
*/ public abstract class AbstractTrafficShapingHandler extends SimpleChannelHandler implements ExternalResourceReleasable { /** * Internal logger */ static InternalLogger logger = InternalLoggerFactory .getInstance(AbstractTrafficShapingHandler.class); /** * Default delay between two checks: 1s */ public static final long DEFAULT_CHECK_INTERVAL = 1000; /** * Default minimal time to wait */ private static final long MINIMAL_WAIT = 10; /** * Traffic Counter */ protected TrafficCounter trafficCounter; /** * ObjectSizeEstimator */ private ObjectSizeEstimator objectSizeEstimator; /** * Timer to associated to any TrafficCounter */ protected Timer timer; /** * used in releaseExternalResources() to cancel the timer */ private volatile Timeout timeout; /** * Limit in B/s to apply to write */ private long writeLimit; /** * Limit in B/s to apply to read */ private long readLimit; /** * Delay between two performance snapshots */ protected long checkInterval = DEFAULT_CHECK_INTERVAL; // default 1 s /** * Boolean associated with the release of this TrafficShapingHandler. * It will be true only once when the releaseExternalRessources is called * to prevent waiting when shutdown. */ final AtomicBoolean release = new AtomicBoolean(false); private void init(ObjectSizeEstimator newObjectSizeEstimator, Timer newTimer, long newWriteLimit, long newReadLimit, long newCheckInterval) { objectSizeEstimator = newObjectSizeEstimator; timer = newTimer; writeLimit = newWriteLimit; readLimit = newReadLimit; checkInterval = newCheckInterval; //logger.warn("TSH: "+writeLimit+":"+readLimit+":"+checkInterval); } /** * * @param newTrafficCounter the TrafficCounter to set */ void setTrafficCounter(TrafficCounter newTrafficCounter) { trafficCounter = newTrafficCounter; } /** * Constructor using default {@link ObjectSizeEstimator} * * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) * @param writeLimit * 0 or a limit in bytes/s * @param readLimit * 0 or a limit in bytes/s * @param checkInterval * The delay between two computations of performances for * channels or 0 if no stats are to be computed */ protected AbstractTrafficShapingHandler(Timer timer, long writeLimit, long readLimit, long checkInterval) { init(new DefaultObjectSizeEstimator(), timer, writeLimit, readLimit, checkInterval); } /** * Constructor using the specified ObjectSizeEstimator * * @param objectSizeEstimator * the {@link ObjectSizeEstimator} that will be used to compute * the size of the message * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) * @param writeLimit * 0 or a limit in bytes/s * @param readLimit * 0 or a limit in bytes/s * @param checkInterval * The delay between two computations of performances for * channels or 0 if no stats are to be computed */ protected AbstractTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer, long writeLimit, long readLimit, long checkInterval) { init(objectSizeEstimator, timer, writeLimit, readLimit, checkInterval); } /** * Constructor using default {@link ObjectSizeEstimator} and using default Check Interval * * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) * @param writeLimit * 0 or a limit in bytes/s * @param readLimit * 0 or a limit in bytes/s */ protected AbstractTrafficShapingHandler(Timer timer, long writeLimit, long readLimit) { init(new DefaultObjectSizeEstimator(), timer, writeLimit, readLimit, DEFAULT_CHECK_INTERVAL); } /** * Constructor using the specified ObjectSizeEstimator and using default Check Interval * * @param objectSizeEstimator * the {@link ObjectSizeEstimator} that will be used to compute * the size of the message * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) * @param writeLimit * 0 or a limit in bytes/s * @param readLimit * 0 or a limit in bytes/s */ protected AbstractTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer, long writeLimit, long readLimit) { init(objectSizeEstimator, timer, writeLimit, readLimit, DEFAULT_CHECK_INTERVAL); } /** * Constructor using default {@link ObjectSizeEstimator} and using NO LIMIT and default Check Interval * * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) */ protected AbstractTrafficShapingHandler(Timer timer) { init(new DefaultObjectSizeEstimator(), timer, 0, 0, DEFAULT_CHECK_INTERVAL); } /** * Constructor using the specified ObjectSizeEstimator and using NO LIMIT and default Check Interval * * @param objectSizeEstimator * the {@link ObjectSizeEstimator} that will be used to compute * the size of the message * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) */ protected AbstractTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer) { init(objectSizeEstimator, timer, 0, 0, DEFAULT_CHECK_INTERVAL); } /** * Constructor using default {@link ObjectSizeEstimator} and using NO LIMIT * * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) * @param checkInterval * The delay between two computations of performances for * channels or 0 if no stats are to be computed */ protected AbstractTrafficShapingHandler(Timer timer, long checkInterval) { init(new DefaultObjectSizeEstimator(), timer, 0, 0, checkInterval); } /** * Constructor using the specified ObjectSizeEstimator and using NO LIMIT * * @param objectSizeEstimator * the {@link ObjectSizeEstimator} that will be used to compute * the size of the message * @param timer * created once for instance like HashedWheelTimer(10, TimeUnit.MILLISECONDS, 1024) * @param checkInterval * The delay between two computations of performances for * channels or 0 if no stats are to be computed */ protected AbstractTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer, long checkInterval) { init(objectSizeEstimator, timer, 0, 0, checkInterval); } /** * Change the underlying limitations and check interval. */ public void configure(long newWriteLimit, long newReadLimit, long newCheckInterval) { configure(newWriteLimit, newReadLimit); configure(newCheckInterval); } /** * Change the underlying limitations. */ public void configure(long newWriteLimit, long newReadLimit) { writeLimit = newWriteLimit; readLimit = newReadLimit; if (trafficCounter != null) { trafficCounter.resetAccounting(System.currentTimeMillis() + 1); } } /** * Change the check interval. */ public void configure(long newCheckInterval) { checkInterval = newCheckInterval; if (trafficCounter != null) { trafficCounter.configure(checkInterval); } } /** * Called each time the accounting is computed from the TrafficCounters. * This method could be used for instance to implement almost real time accounting. * * @param counter * the TrafficCounter that computes its performance */ protected void doAccounting(TrafficCounter counter) { // NOOP by default } /** * Class to implement setReadable at fix time */ private class ReopenReadTimerTask implements TimerTask { final ChannelHandlerContext ctx; ReopenReadTimerTask(ChannelHandlerContext ctx) { this.ctx = ctx; } public void run(Timeout timeoutArg) throws Exception { //logger.warn("Start RRTT: "+release.get()); if (release.get()) { return; } /* logger.warn("WAKEUP! "+ (ctx != null && ctx.getChannel() != null && ctx.getChannel().isConnected())); */ if (ctx != null && ctx.getChannel() != null && ctx.getChannel().isConnected()) { //logger.warn(" setReadable TRUE: "); // readSuspended = false; ctx.setAttachment(null); ctx.getChannel().setReadable(true); } } } /** * @return the time that should be necessary to wait to respect limit. Can be negative time */ private static long getTimeToWait(long limit, long bytes, long lastTime, long curtime) { long interval = curtime - lastTime; if (interval <= 0) { // Time is too short, so just lets continue return 0; } return (bytes * 1000 / limit - interval) / 10 * 10; } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent evt) throws Exception { try { long curtime = System.currentTimeMillis(); long size = objectSizeEstimator.estimateSize(evt.getMessage()); if (trafficCounter != null) { trafficCounter.bytesRecvFlowControl(size); if (readLimit == 0) { // no action return; } // compute the number of ms to wait before reopening the channel long wait = getTimeToWait(readLimit, trafficCounter.getCurrentReadBytes(), trafficCounter.getLastTime(), curtime); if (wait >= MINIMAL_WAIT) { // At least 10ms seems a minimal // time in order to Channel channel = ctx.getChannel(); // try to limit the traffic if (channel != null && channel.isConnected()) { // Channel version if (timer == null) { // Sleep since no executor // logger.warn("Read sleep since no timer for "+wait+" ms for "+this); if (release.get()) { return; } Thread.sleep(wait); return; } if (ctx.getAttachment() == null) { // readSuspended = true; ctx.setAttachment(Boolean.TRUE); channel.setReadable(false); // logger.warn("Read will wakeup after "+wait+" ms "+this); TimerTask timerTask = new ReopenReadTimerTask(ctx); timeout = timer.newTimeout(timerTask, wait, TimeUnit.MILLISECONDS); } else { // should be waiting: but can occurs sometime so as // a FIX // logger.warn("Read sleep ok but should not be here: "+wait+" "+this); if (release.get()) { return; } Thread.sleep(wait); } } else { // Not connected or no channel // logger.warn("Read sleep "+wait+" ms for "+this); if (release.get()) { return; } Thread.sleep(wait); } } } } finally { // The message is then just passed to the next handler super.messageReceived(ctx, evt); } } @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent evt) throws Exception { try { long curtime = System.currentTimeMillis(); long size = objectSizeEstimator.estimateSize(evt.getMessage()); if (trafficCounter != null) { trafficCounter.bytesWriteFlowControl(size); if (writeLimit == 0) { return; } // compute the number of ms to wait before continue with the // channel long wait = getTimeToWait(writeLimit, trafficCounter.getCurrentWrittenBytes(), trafficCounter.getLastTime(), curtime); if (wait >= MINIMAL_WAIT) { // Global or Channel if (release.get()) { return; } Thread.sleep(wait); } } } finally { // The message is then just passed to the next handler super.writeRequested(ctx, evt); } } @Override public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { ChannelStateEvent cse = (ChannelStateEvent) e; if (cse.getState() == ChannelState.INTEREST_OPS && (((Integer) cse.getValue()).intValue() & Channel.OP_READ) != 0) { // setReadable(true) requested boolean readSuspended = ctx.getAttachment() != null; if (readSuspended) { // Drop the request silently if this handler has // set the flag. e.getFuture().setSuccess(); return; } } } super.handleDownstream(ctx, e); } /** * * @return the current TrafficCounter (if * channel is still connected) */ public TrafficCounter getTrafficCounter() { return trafficCounter; } public void releaseExternalResources() { if (trafficCounter != null) { trafficCounter.stop(); } release.set(true); if (timeout != null) { timeout.cancel(); } timer.stop(); } @Override public String toString() { return "TrafficShaping with Write Limit: " + writeLimit + " Read Limit: " + readLimit + " and Counter: " + (trafficCounter != null? trafficCounter.toString() : "none"); } } ChannelTrafficShapingHandler.java000066400000000000000000000130441225554127700340770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/traffic/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.traffic; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.handler.execution.ExecutionHandler; import org.jboss.netty.handler.execution.MemoryAwareThreadPoolExecutor; import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; import org.jboss.netty.util.ObjectSizeEstimator; import org.jboss.netty.util.Timer; /** * This implementation of the {@link AbstractTrafficShapingHandler} is for channel * traffic shaping, that is to say a per channel limitation of the bandwidth.

* * The general use should be as follow:
*
    *
  • Add in your pipeline a new ChannelTrafficShapingHandler, before a recommended {@link ExecutionHandler} (like * {@link OrderedMemoryAwareThreadPoolExecutor} or {@link MemoryAwareThreadPoolExecutor}).
    * ChannelTrafficShapingHandler myHandler = new ChannelTrafficShapingHandler(timer);
    * timer could be created using HashedWheelTimer
    * pipeline.addLast("CHANNEL_TRAFFIC_SHAPING", myHandler);

    * * Note that this handler has a Pipeline Coverage of "one" which means a new handler must be created * for each new channel as the counter cannot be shared among all channels. For instance, if you have a * {@link ChannelPipelineFactory}, you should create a new ChannelTrafficShapingHandler in this * {@link ChannelPipelineFactory} each time getPipeline() method is called.

    * * Other arguments can be passed like write or read limitation (in bytes/s where 0 means no limitation) * or the check interval (in millisecond) that represents the delay between two computations of the * bandwidth and so the call back of the doAccounting method (0 means no accounting at all).

    * * A value of 0 means no accounting for checkInterval. If you need traffic shaping but no such accounting, * it is recommended to set a positive value, even if it is high since the precision of the * Traffic Shaping depends on the period where the traffic is computed. The highest the interval, * the less precise the traffic shaping will be. It is suggested as higher value something close * to 5 or 10 minutes.
    *
  • *
  • When you shutdown your application, release all the external resources (except the timer internal itself) * by calling:
    * myHandler.releaseExternalResources();
    *
  • *

*/ public class ChannelTrafficShapingHandler extends AbstractTrafficShapingHandler { public ChannelTrafficShapingHandler(Timer timer, long writeLimit, long readLimit, long checkInterval) { super(timer, writeLimit, readLimit, checkInterval); } public ChannelTrafficShapingHandler(Timer timer, long writeLimit, long readLimit) { super(timer, writeLimit, readLimit); } public ChannelTrafficShapingHandler(Timer timer, long checkInterval) { super(timer, checkInterval); } public ChannelTrafficShapingHandler(Timer timer) { super(timer); } public ChannelTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer, long writeLimit, long readLimit, long checkInterval) { super(objectSizeEstimator, timer, writeLimit, readLimit, checkInterval); } public ChannelTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer, long writeLimit, long readLimit) { super(objectSizeEstimator, timer, writeLimit, readLimit); } public ChannelTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer, long checkInterval) { super(objectSizeEstimator, timer, checkInterval); } public ChannelTrafficShapingHandler( ObjectSizeEstimator objectSizeEstimator, Timer timer) { super(objectSizeEstimator, timer); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (trafficCounter != null) { trafficCounter.stop(); } super.channelClosed(ctx, e); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // readSuspended = true; ctx.setAttachment(Boolean.TRUE); ctx.getChannel().setReadable(false); if (trafficCounter == null) { // create a new counter now if (timer != null) { trafficCounter = new TrafficCounter(this, timer, "ChannelTC" + ctx.getChannel().getId(), checkInterval); } } if (trafficCounter != null) { trafficCounter.start(); } super.channelConnected(ctx, e); // readSuspended = false; ctx.setAttachment(null); ctx.getChannel().setReadable(true); } } GlobalTrafficShapingHandler.java000066400000000000000000000117371225554127700337360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/traffic/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.traffic; import org.jboss.netty.channel.ChannelHandler.Sharable; import org.jboss.netty.handler.execution.ExecutionHandler; import org.jboss.netty.handler.execution.MemoryAwareThreadPoolExecutor; import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; import org.jboss.netty.util.ObjectSizeEstimator; import org.jboss.netty.util.Timer; /** * This implementation of the {@link AbstractTrafficShapingHandler} is for global * traffic shaping, that is to say a global limitation of the bandwidth, whatever * the number of opened channels.

* * The general use should be as follow:
*
    *
  • Create your unique GlobalTrafficShapingHandler like:

    * GlobalTrafficShapingHandler myHandler = new GlobalTrafficShapingHandler(timer);

    * timer could be created using HashedWheelTimer
    * pipeline.addLast("GLOBAL_TRAFFIC_SHAPING", myHandler);

    * * Note that this handler has a Pipeline Coverage of "all" which means only one such handler must be created * and shared among all channels as the counter must be shared among all channels.

    * * Other arguments can be passed like write or read limitation (in bytes/s where 0 means no limitation) * or the check interval (in millisecond) that represents the delay between two computations of the * bandwidth and so the call back of the doAccounting method (0 means no accounting at all).

    * * A value of 0 means no accounting for checkInterval. If you need traffic shaping but no such accounting, * it is recommended to set a positive value, even if it is high since the precision of the * Traffic Shaping depends on the period where the traffic is computed. The highest the interval, * the less precise the traffic shaping will be. It is suggested as higher value something close * to 5 or 10 minutes.
    *
  • *
  • Add it in your pipeline, before a recommended {@link ExecutionHandler} (like * {@link OrderedMemoryAwareThreadPoolExecutor} or {@link MemoryAwareThreadPoolExecutor}).
    * pipeline.addLast("GLOBAL_TRAFFIC_SHAPING", myHandler);

    *
  • *
  • When you shutdown your application, release all the external resources * by calling:
    * myHandler.releaseExternalResources();
    *
  • *

*/ @Sharable public class GlobalTrafficShapingHandler extends AbstractTrafficShapingHandler { /** * Create the global TrafficCounter */ void createGlobalTrafficCounter() { TrafficCounter tc; if (timer != null) { tc = new TrafficCounter(this, timer, "GlobalTC", checkInterval); setTrafficCounter(tc); tc.start(); } } public GlobalTrafficShapingHandler(Timer timer, long writeLimit, long readLimit, long checkInterval) { super(timer, writeLimit, readLimit, checkInterval); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(Timer timer, long writeLimit, long readLimit) { super(timer, writeLimit, readLimit); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(Timer timer, long checkInterval) { super(timer, checkInterval); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(Timer timer) { super(timer); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, Timer timer, long writeLimit, long readLimit, long checkInterval) { super(objectSizeEstimator, timer, writeLimit, readLimit, checkInterval); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, Timer timer, long writeLimit, long readLimit) { super(objectSizeEstimator, timer, writeLimit, readLimit); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, Timer timer, long checkInterval) { super(objectSizeEstimator, timer, checkInterval); createGlobalTrafficCounter(); } public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, Timer timer) { super(objectSizeEstimator, timer); createGlobalTrafficCounter(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/traffic/TrafficCounter.java000066400000000000000000000255071225554127700314240ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.traffic; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; /** * TrafficCounter is associated with {@link AbstractTrafficShapingHandler}.
*
* A TrafficCounter has for goal to count the traffic in order to enable to limit the traffic or not, * globally or per channel. It compute statistics on read and written bytes at the specified * interval and call back the {@link AbstractTrafficShapingHandler} doAccounting method at every * specified interval. If this interval is set to 0, therefore no accounting will be done and only * statistics will be computed at each receive or write operations. */ public class TrafficCounter { /** * Current written bytes */ private final AtomicLong currentWrittenBytes = new AtomicLong(); /** * Current read bytes */ private final AtomicLong currentReadBytes = new AtomicLong(); /** * Long life written bytes */ private final AtomicLong cumulativeWrittenBytes = new AtomicLong(); /** * Long life read bytes */ private final AtomicLong cumulativeReadBytes = new AtomicLong(); /** * Last Time where cumulative bytes where reset to zero */ private long lastCumulativeTime; /** * Last writing bandwidth */ private long lastWriteThroughput; /** * Last reading bandwidth */ private long lastReadThroughput; /** * Last Time Check taken */ private final AtomicLong lastTime = new AtomicLong(); /** * Last written bytes number during last check interval */ private long lastWrittenBytes; /** * Last read bytes number during last check interval */ private long lastReadBytes; /** * Delay between two captures */ final AtomicLong checkInterval = new AtomicLong( AbstractTrafficShapingHandler.DEFAULT_CHECK_INTERVAL); // default 1 s /** * Name of this Monitor */ final String name; /** * The associated TrafficShapingHandler */ private final AbstractTrafficShapingHandler trafficShapingHandler; /** * One Timer for all Counter */ private final Timer timer; // replace executor /** * Monitor created once in start() */ private TimerTask timerTask; /** * used in stop() to cancel the timer */ private volatile Timeout timeout; /** * Is Monitor active */ final AtomicBoolean monitorActive = new AtomicBoolean(); /** * Class to implement monitoring at fix delay * */ private static class TrafficMonitoringTask implements TimerTask { /** * The associated TrafficShapingHandler */ private final AbstractTrafficShapingHandler trafficShapingHandler1; /** * The associated TrafficCounter */ private final TrafficCounter counter; protected TrafficMonitoringTask( AbstractTrafficShapingHandler trafficShapingHandler, TrafficCounter counter) { trafficShapingHandler1 = trafficShapingHandler; this.counter = counter; } public void run(Timeout timeout) throws Exception { if (!counter.monitorActive.get()) { return; } long endTime = System.currentTimeMillis(); counter.resetAccounting(endTime); if (trafficShapingHandler1 != null) { trafficShapingHandler1.doAccounting(counter); } counter.timer.newTimeout(this, counter.checkInterval.get(), TimeUnit.MILLISECONDS); } } /** * Start the monitoring process */ public void start() { synchronized (lastTime) { if (monitorActive.get()) { return; } lastTime.set(System.currentTimeMillis()); if (checkInterval.get() > 0) { monitorActive.set(true); timerTask = new TrafficMonitoringTask(trafficShapingHandler, this); timeout = timer.newTimeout(timerTask, checkInterval.get(), TimeUnit.MILLISECONDS); } } } /** * Stop the monitoring process */ public void stop() { synchronized (lastTime) { if (!monitorActive.get()) { return; } monitorActive.set(false); resetAccounting(System.currentTimeMillis()); if (trafficShapingHandler != null) { trafficShapingHandler.doAccounting(this); } if (timeout != null) { timeout.cancel(); } } } /** * Reset the accounting on Read and Write */ void resetAccounting(long newLastTime) { synchronized (lastTime) { long interval = newLastTime - lastTime.getAndSet(newLastTime); if (interval == 0) { // nothing to do return; } lastReadBytes = currentReadBytes.getAndSet(0); lastWrittenBytes = currentWrittenBytes.getAndSet(0); lastReadThroughput = lastReadBytes / interval * 1000; // nb byte / checkInterval in ms * 1000 (1s) lastWriteThroughput = lastWrittenBytes / interval * 1000; // nb byte / checkInterval in ms * 1000 (1s) } } /** * Constructor with the {@link AbstractTrafficShapingHandler} that hosts it, the Timer to use, its * name, the checkInterval between two computations in millisecond * @param trafficShapingHandler the associated AbstractTrafficShapingHandler * @param timer * Could be a HashedWheelTimer * @param name * the name given to this monitor * @param checkInterval * the checkInterval in millisecond between two computations */ public TrafficCounter(AbstractTrafficShapingHandler trafficShapingHandler, Timer timer, String name, long checkInterval) { this.trafficShapingHandler = trafficShapingHandler; this.timer = timer; this.name = name; lastCumulativeTime = System.currentTimeMillis(); configure(checkInterval); } /** * Change checkInterval between * two computations in millisecond */ public void configure(long newcheckInterval) { long newInterval = newcheckInterval / 10 * 10; if (checkInterval.get() != newInterval) { checkInterval.set(newInterval); if (newInterval <= 0) { stop(); // No more active monitoring lastTime.set(System.currentTimeMillis()); } else { // Start if necessary start(); } } } /** * Computes counters for Read. * * @param recv * the size in bytes to read */ void bytesRecvFlowControl(long recv) { currentReadBytes.addAndGet(recv); cumulativeReadBytes.addAndGet(recv); } /** * Computes counters for Write. * * @param write * the size in bytes to write */ void bytesWriteFlowControl(long write) { currentWrittenBytes.addAndGet(write); cumulativeWrittenBytes.addAndGet(write); } /** * * @return the current checkInterval between two computations of traffic counter * in millisecond */ public long getCheckInterval() { return checkInterval.get(); } /** * * @return the Read Throughput in bytes/s computes in the last check interval */ public long getLastReadThroughput() { return lastReadThroughput; } /** * * @return the Write Throughput in bytes/s computes in the last check interval */ public long getLastWriteThroughput() { return lastWriteThroughput; } /** * * @return the number of bytes read during the last check Interval */ public long getLastReadBytes() { return lastReadBytes; } /** * * @return the number of bytes written during the last check Interval */ public long getLastWrittenBytes() { return lastWrittenBytes; } /** * * @return the current number of bytes read since the last checkInterval */ public long getCurrentReadBytes() { return currentReadBytes.get(); } /** * * @return the current number of bytes written since the last check Interval */ public long getCurrentWrittenBytes() { return currentWrittenBytes.get(); } /** * @return the Time in millisecond of the last check as of System.currentTimeMillis() */ public long getLastTime() { return lastTime.get(); } /** * @return the cumulativeWrittenBytes */ public long getCumulativeWrittenBytes() { return cumulativeWrittenBytes.get(); } /** * @return the cumulativeReadBytes */ public long getCumulativeReadBytes() { return cumulativeReadBytes.get(); } /** * @return the lastCumulativeTime in millisecond as of System.currentTimeMillis() * when the cumulative counters were reset to 0. */ public long getLastCumulativeTime() { return lastCumulativeTime; } /** * Reset both read and written cumulative bytes counters and the associated time. */ public void resetCumulativeTime() { lastCumulativeTime = System.currentTimeMillis(); cumulativeReadBytes.set(0); cumulativeWrittenBytes.set(0); } /** * @return the name */ public String getName() { return name; } /** * String information */ @Override public String toString() { return "Monitor " + name + " Current Speed Read: " + (lastReadThroughput >> 10) + " KB/s, Write: " + (lastWriteThroughput >> 10) + " KB/s Current Read: " + (currentReadBytes.get() >> 10) + " KB Current Write: " + (currentWrittenBytes.get() >> 10) + " KB"; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/handler/traffic/package-info.java000066400000000000000000000133731225554127700310300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Implementation of a Traffic Shaping Handler and Dynamic Statistics.
*

* * *

The main goal of this package is to allow to shape the traffic (bandwidth limitation), * but also to get statistics on how many bytes are read or written. Both functions can * be active or inactive (traffic or statistics).

* *

Two classes implement this behavior:
*

    *
  • {@link org.jboss.netty.handler.traffic.TrafficCounter}: this class implements the counters * needed by the handlers. It can be accessed to get some extra information like the read or * write bytes since last check, the read and write bandwidth from last check...


  • * *
  • {@link org.jboss.netty.handler.traffic.AbstractTrafficShapingHandler}: this abstract class * implements the kernel of the traffic shaping. It could be extended to fit your needs. Two * classes are proposed as default implementations: see * {@link org.jboss.netty.handler.traffic.ChannelTrafficShapingHandler} and * {@link org.jboss.netty.handler.traffic.GlobalTrafficShapingHandler} respectively for * Channel traffic shaping and Global traffic shaping.


  • * * The insertion in the pipeline of one of those handlers can be wherever you want, but * it must be placed before any {@link org.jboss.netty.handler.execution.MemoryAwareThreadPoolExecutor} * in your pipeline.
    * It is really recommended to have such a * {@link org.jboss.netty.handler.execution.MemoryAwareThreadPoolExecutor} * (either non ordered or * {@link org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor} * ) in your pipeline * when you want to use this feature with some real traffic shaping, since it will allow to relax the constraint on * NioWorker to do other jobs if necessary.
    * Instead, if you don't, you can have the following situation: if there are more clients * connected and doing data transfer (either in read or write) than NioWorker, your global performance can be under * your specifications or even sometimes it will block for a while which can turn to "timeout" operations. * For instance, let says that you've got 2 NioWorkers, and 10 clients wants to send data to your server. * If you set a bandwidth limitation of 100KB/s for each channel (client), you could have a final limitation of about * 60KB/s for each channel since NioWorkers are stopping by this handler.
    * When it is used as a read traffic shaper, the handler will set the channel as not readable, so as to relax the * NioWorkers.

    * An {@link org.jboss.netty.util.ObjectSizeEstimator} can be passed at construction to specify what * is the size of the object to be read or write accordingly to the type of * object. If not specified, it will used the {@link org.jboss.netty.util.DefaultObjectSizeEstimator} * implementation.

    *

* *

Standard use could be as follow:

* *

    *
  • To activate or deactivate the traffic shaping, change the value corresponding to your desire as * [Global or per Channel] [Write or Read] Limitation in byte/s.

  • * A value of 0 * stands for no limitation, so the traffic shaping is deactivate (on what you specified).
    * You can either change those values with the method configure in * {@link org.jboss.netty.handler.traffic.AbstractTrafficShapingHandler}.
    *
    * *
  • To activate or deactivate the statistics, you can adjust the delay to a low (suggested not less than 200ms * for efficiency reasons) or a high value (let say 24H in millisecond is huge enough to not get the problem) * or even using 0 which means no computation will be done.

  • * If you want to do anything with this statistics, just override the doAccounting method.
    * This interval can be changed either from the method configure in * {@link org.jboss.netty.handler.traffic.AbstractTrafficShapingHandler} * or directly using the method configure of {@link org.jboss.netty.handler.traffic.TrafficCounter}.

    * *



* *

So in your application you will create your own TrafficShapingHandler and set the values to fit your needs.

* XXXXXTrafficShapingHandler myHandler = new XXXXXTrafficShapingHandler(timer);

* timer could be created using HashedWheelTimer and XXXXX could be either * Global or Channel
* pipeline.addLast("XXXXX_TRAFFIC_SHAPING", myHandler);
* ...
* pipeline.addLast("MemoryExecutor",new ExecutionHandler(memoryAwareThreadPoolExecutor));

*

Note that a new {@link org.jboss.netty.handler.traffic.ChannelTrafficShapingHandler} must be * created for each new channel, but only one {@link org.jboss.netty.handler.traffic.GlobalTrafficShapingHandler} * must be created for all channels.

* *

Note also that you can create different GlobalTrafficShapingHandler if you want to separate classes of * channels (for instance either from business point of view or from bind address point of view).

* * @apiviz.exclude ^java\.lang\. */ package org.jboss.netty.handler.traffic; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/000077500000000000000000000000001225554127700242255ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/AbstractInternalLogger.java000066400000000000000000000043731225554127700314770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; /** * A skeletal implementation of {@link InternalLogger}. This class implements * all methods that have a {@link InternalLogLevel} parameter by default to call * specific logger methods such as {@link #info(String)} or {@link #isInfoEnabled()}. */ public abstract class AbstractInternalLogger implements InternalLogger { /** * Creates a new instance. */ protected AbstractInternalLogger() { } public boolean isEnabled(InternalLogLevel level) { switch (level) { case DEBUG: return isDebugEnabled(); case INFO: return isInfoEnabled(); case WARN: return isWarnEnabled(); case ERROR: return isErrorEnabled(); default: throw new Error(); } } public void log(InternalLogLevel level, String msg, Throwable cause) { switch (level) { case DEBUG: debug(msg, cause); break; case INFO: info(msg, cause); break; case WARN: warn(msg, cause); break; case ERROR: error(msg, cause); break; default: throw new Error(); } } public void log(InternalLogLevel level, String msg) { switch (level) { case DEBUG: debug(msg); break; case INFO: info(msg); break; case WARN: warn(msg); break; case ERROR: error(msg); break; default: throw new Error(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/CommonsLogger.java000066400000000000000000000041031225554127700276410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.apache.commons.logging.Log; /** * Apache Commons Logging * logger. */ class CommonsLogger extends AbstractInternalLogger { private final Log logger; private final String loggerName; CommonsLogger(Log logger, String loggerName) { this.logger = logger; this.loggerName = loggerName; } public void debug(String msg) { logger.debug(msg); } public void debug(String msg, Throwable cause) { logger.debug(msg, cause); } public void error(String msg) { logger.error(msg); } public void error(String msg, Throwable cause) { logger.error(msg, cause); } public void info(String msg) { logger.info(msg); } public void info(String msg, Throwable cause) { logger.info(msg, cause); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public void warn(String msg) { logger.warn(msg); } public void warn(String msg, Throwable cause) { logger.warn(msg, cause); } @Override public String toString() { return loggerName; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/CommonsLoggerFactory.java000066400000000000000000000021631225554127700311750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Logger factory which creates an * Apache Commons Logging * logger. */ public class CommonsLoggerFactory extends InternalLoggerFactory { @Override public InternalLogger newInstance(String name) { final Log logger = LogFactory.getLog(name); return new CommonsLogger(logger, name); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/InternalLogLevel.java000066400000000000000000000017161225554127700303030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; /** * The log level that {@link InternalLogger} can log at. */ public enum InternalLogLevel { /** * 'DEBUG' log level. */ DEBUG, /** * 'INFO' log level. */ INFO, /** * 'WARN' log level. */ WARN, /** * 'ERROR' log level. */ ERROR } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/InternalLogger.java000066400000000000000000000044051225554127700300070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; /** * Internal-use-only logger used by Netty. DO NOT * access this class outside of Netty. */ public interface InternalLogger { /** * Returns {@code true} if a DEBUG level message is logged. */ boolean isDebugEnabled(); /** * Returns {@code true} if an INFO level message is logged. */ boolean isInfoEnabled(); /** * Returns {@code true} if a WARN level message is logged. */ boolean isWarnEnabled(); /** * Returns {@code true} if an ERROR level message is logged. */ boolean isErrorEnabled(); /** * Returns {@code true} if the specified log level message is logged. */ boolean isEnabled(InternalLogLevel level); /** * Logs a DEBUG level message. */ void debug(String msg); /** * Logs a DEBUG level message. */ void debug(String msg, Throwable cause); /** * Logs an INFO level message. */ void info(String msg); /** * Logs an INFO level message. */ void info(String msg, Throwable cause); /** * Logs a WARN level message. */ void warn(String msg); /** * Logs a WARN level message. */ void warn(String msg, Throwable cause); /** * Logs an ERROR level message. */ void error(String msg); /** * Logs an ERROR level message. */ void error(String msg, Throwable cause); /** * Logs a message. */ void log(InternalLogLevel level, String msg); /** * Logs a message. */ void log(InternalLogLevel level, String msg, Throwable cause); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/InternalLoggerFactory.java000066400000000000000000000116111225554127700313340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.jboss.netty.util.internal.StackTraceSimplifier; /** * Creates an {@link InternalLogger} or changes the default factory * implementation. This factory allows you to choose what logging framework * Netty should use. The default factory is {@link JdkLoggerFactory}. * You can change it to your preferred logging framework before other Netty * classes are loaded: *
 * {@link InternalLoggerFactory}.setDefaultFactory(new {@link Log4JLoggerFactory}());
 * 
* Please note that the new default factory is effective only for the classes * which were loaded after the default factory is changed. Therefore, * {@link #setDefaultFactory(InternalLoggerFactory)} should be called as early * as possible and shouldn't be called more than once. * * @apiviz.landmark * @apiviz.has org.jboss.netty.logging.InternalLogger oneway - - creates */ public abstract class InternalLoggerFactory { private static volatile InternalLoggerFactory defaultFactory = new JdkLoggerFactory(); static { // Load the dependent classes in advance to avoid the case where // the VM fails to load the required classes because of too many open // files. StackTraceSimplifier.simplify(new Exception()); } /** * Returns the default factory. The initial default factory is * {@link JdkLoggerFactory}. */ public static InternalLoggerFactory getDefaultFactory() { return defaultFactory; } /** * Changes the default factory. */ public static void setDefaultFactory(InternalLoggerFactory defaultFactory) { if (defaultFactory == null) { throw new NullPointerException("defaultFactory"); } InternalLoggerFactory.defaultFactory = defaultFactory; } /** * Creates a new logger instance with the name of the specified class. */ public static InternalLogger getInstance(Class clazz) { return getInstance(clazz.getName()); } /** * Creates a new logger instance with the specified name. */ public static InternalLogger getInstance(String name) { final InternalLogger logger = getDefaultFactory().newInstance(name); return new InternalLogger() { public void debug(String msg) { logger.debug(msg); } public void debug(String msg, Throwable cause) { StackTraceSimplifier.simplify(cause); logger.debug(msg, cause); } public void error(String msg) { logger.error(msg); } public void error(String msg, Throwable cause) { StackTraceSimplifier.simplify(cause); logger.error(msg, cause); } public void info(String msg) { logger.info(msg); } public void info(String msg, Throwable cause) { StackTraceSimplifier.simplify(cause); logger.info(msg, cause); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public void warn(String msg) { logger.warn(msg); } public void warn(String msg, Throwable cause) { StackTraceSimplifier.simplify(cause); logger.warn(msg, cause); } public boolean isEnabled(InternalLogLevel level) { return logger.isEnabled(level); } public void log(InternalLogLevel level, String msg) { logger.log(level, msg); } public void log(InternalLogLevel level, String msg, Throwable cause) { StackTraceSimplifier.simplify(cause); logger.log(level, msg, cause); } }; } /** * Creates a new logger instance with the specified name. */ public abstract InternalLogger newInstance(String name); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/JBossLogger.java000066400000000000000000000040521225554127700272510ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.jboss.logging.Logger; /** * JBoss Logging * logger. */ class JBossLogger extends AbstractInternalLogger { private final Logger logger; JBossLogger(Logger logger) { this.logger = logger; } public void debug(String msg) { logger.debug(msg); } public void debug(String msg, Throwable cause) { logger.debug(msg, cause); } public void error(String msg) { logger.error(msg); } public void error(String msg, Throwable cause) { logger.error(msg, cause); } public void info(String msg) { logger.info(msg); } public void info(String msg, Throwable cause) { logger.info(msg, cause); } @SuppressWarnings("deprecation") public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isErrorEnabled() { return true; } @SuppressWarnings("deprecation") public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return true; } public void warn(String msg) { logger.warn(msg); } public void warn(String msg, Throwable cause) { logger.warn(msg, cause); } @Override public String toString() { return String.valueOf(logger.getName()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/JBossLoggerFactory.java000066400000000000000000000021041225554127700305750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.jboss.logging.Logger; /** * Logger factory which creates a * JBoss Logging * logger. */ public class JBossLoggerFactory extends InternalLoggerFactory { @Override public InternalLogger newInstance(String name) { final Logger logger = Logger.getLogger(name); return new JBossLogger(logger); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/JdkLogger.java000066400000000000000000000046161225554127700267470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import java.util.logging.Level; import java.util.logging.Logger; /** * java.util.logging * logger. */ class JdkLogger extends AbstractInternalLogger { private final Logger logger; private final String loggerName; JdkLogger(Logger logger, String loggerName) { this.logger = logger; this.loggerName = loggerName; } public void debug(String msg) { logger.logp(Level.FINE, loggerName, null, msg); } public void debug(String msg, Throwable cause) { logger.logp(Level.FINE, loggerName, null, msg, cause); } public void error(String msg) { logger.logp(Level.SEVERE, loggerName, null, msg); } public void error(String msg, Throwable cause) { logger.logp(Level.SEVERE, loggerName, null, msg, cause); } public void info(String msg) { logger.logp(Level.INFO, loggerName, null, msg); } public void info(String msg, Throwable cause) { logger.logp(Level.INFO, loggerName, null, msg, cause); } public boolean isDebugEnabled() { return logger.isLoggable(Level.FINE); } public boolean isErrorEnabled() { return logger.isLoggable(Level.SEVERE); } public boolean isInfoEnabled() { return logger.isLoggable(Level.INFO); } public boolean isWarnEnabled() { return logger.isLoggable(Level.WARNING); } public void warn(String msg) { logger.logp(Level.WARNING, loggerName, null, msg); } public void warn(String msg, Throwable cause) { logger.logp(Level.WARNING, loggerName, null, msg, cause); } @Override public String toString() { return loggerName; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/JdkLoggerFactory.java000066400000000000000000000021261225554127700302710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import java.util.logging.Logger; /** * Logger factory which creates a * java.util.logging * logger. */ public class JdkLoggerFactory extends InternalLoggerFactory { @Override public InternalLogger newInstance(String name) { final Logger logger = Logger.getLogger(name); return new JdkLogger(logger, name); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/Log4JLogger.java000066400000000000000000000037231225554127700271540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.apache.log4j.Logger; /** * Apache Log4J * logger. */ class Log4JLogger extends AbstractInternalLogger { private final Logger logger; Log4JLogger(Logger logger) { this.logger = logger; } public void debug(String msg) { logger.debug(msg); } public void debug(String msg, Throwable cause) { logger.debug(msg, cause); } public void error(String msg) { logger.error(msg); } public void error(String msg, Throwable cause) { logger.error(msg, cause); } public void info(String msg) { logger.info(msg); } public void info(String msg, Throwable cause) { logger.info(msg, cause); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isErrorEnabled() { return true; } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return true; } public void warn(String msg) { logger.warn(msg); } public void warn(String msg, Throwable cause) { logger.warn(msg, cause); } @Override public String toString() { return String.valueOf(logger.getName()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/Log4JLoggerFactory.java000066400000000000000000000020671225554127700305040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.apache.log4j.Logger; /** * Logger factory which creates an * Apache Log4J * logger. */ public class Log4JLoggerFactory extends InternalLoggerFactory { @Override public InternalLogger newInstance(String name) { final Logger logger = Logger.getLogger(name); return new Log4JLogger(logger); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/OsgiLogger.java000066400000000000000000000072031225554127700271330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.osgi.service.log.LogService; /** * OSGi {@link LogService} logger. */ class OsgiLogger extends AbstractInternalLogger { private final OsgiLoggerFactory parent; private final InternalLogger fallback; private final String name; private final String prefix; OsgiLogger(OsgiLoggerFactory parent, String name, InternalLogger fallback) { this.parent = parent; this.name = name; this.fallback = fallback; prefix = '[' + name + "] "; } public void debug(String msg) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_DEBUG, prefix + msg); } else { fallback.debug(msg); } } public void debug(String msg, Throwable cause) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_DEBUG, prefix + msg, cause); } else { fallback.debug(msg, cause); } } public void error(String msg) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_ERROR, prefix + msg); } else { fallback.error(msg); } } public void error(String msg, Throwable cause) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_ERROR, prefix + msg, cause); } else { fallback.error(msg, cause); } } public void info(String msg) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_INFO, prefix + msg); } else { fallback.info(msg); } } public void info(String msg, Throwable cause) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_INFO, prefix + msg, cause); } else { fallback.info(msg, cause); } } public boolean isDebugEnabled() { return true; } public boolean isErrorEnabled() { return true; } public boolean isInfoEnabled() { return true; } public boolean isWarnEnabled() { return true; } public void warn(String msg) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_WARNING, prefix + msg); } else { fallback.warn(msg); } } public void warn(String msg, Throwable cause) { LogService logService = parent.getLogService(); if (logService != null) { logService.log(LogService.LOG_WARNING, prefix + msg, cause); } else { fallback.warn(msg, cause); } } @Override public String toString() { return name; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/OsgiLoggerFactory.java000066400000000000000000000053061225554127700304650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTracker; /** * Logger factory which creates an OSGi * {@link LogService} logger. */ public class OsgiLoggerFactory extends InternalLoggerFactory { private final ServiceTracker logServiceTracker; private final InternalLoggerFactory fallback; volatile LogService logService; public OsgiLoggerFactory(BundleContext ctx) { this(ctx, null); } public OsgiLoggerFactory(BundleContext ctx, InternalLoggerFactory fallback) { if (ctx == null) { throw new NullPointerException("ctx"); } if (fallback == null) { fallback = InternalLoggerFactory.getDefaultFactory(); if (fallback instanceof OsgiLoggerFactory) { fallback = new JdkLoggerFactory(); } } this.fallback = fallback; logServiceTracker = new ServiceTracker( ctx, "org.osgi.service.log.LogService", null) { @Override public Object addingService(ServiceReference reference) { LogService service = (LogService) super.addingService(reference); logService = service; return service; } @Override public void removedService(ServiceReference reference, Object service) { logService = null; } }; logServiceTracker.open(); } public InternalLoggerFactory getFallback() { return fallback; } public LogService getLogService() { return logService; } public void destroy() { logService = null; logServiceTracker.close(); } @Override public InternalLogger newInstance(String name) { return new OsgiLogger(this, name, fallback.newInstance(name)); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/Slf4JLogger.java000066400000000000000000000037161225554127700271610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.slf4j.Logger; /** * SLF4J logger. */ class Slf4JLogger extends AbstractInternalLogger { private final Logger logger; Slf4JLogger(Logger logger) { this.logger = logger; } public void debug(String msg) { logger.debug(msg); } public void debug(String msg, Throwable cause) { logger.debug(msg, cause); } public void error(String msg) { logger.error(msg); } public void error(String msg, Throwable cause) { logger.error(msg, cause); } public void info(String msg) { logger.info(msg); } public void info(String msg, Throwable cause) { logger.info(msg, cause); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public void warn(String msg) { logger.warn(msg); } public void warn(String msg, Throwable cause) { logger.warn(msg, cause); } @Override public String toString() { return String.valueOf(logger.getName()); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/Slf4JLoggerFactory.java000066400000000000000000000020641225554127700305040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Logger factory which creates a SLF4J * logger. */ public class Slf4JLoggerFactory extends InternalLoggerFactory { @Override public InternalLogger newInstance(String name) { final Logger logger = LoggerFactory.getLogger(name); return new Slf4JLogger(logger); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/logging/package-info.java000066400000000000000000000014731225554127700274210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Simplistic internal-use-only logging layer which allows a user to * decide what logging framework Netty should use. * * @apiviz.hidden */ package org.jboss.netty.logging; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/000077500000000000000000000000001225554127700235545ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/CharsetUtil.java000066400000000000000000000103721225554127700266510ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; import java.util.IdentityHashMap; import java.util.Map; /** * A utility class that provides various common operations and constants * related with {@link Charset} and its relevant classes. */ public final class CharsetUtil { /** * 16-bit UTF (UCS Transformation Format) whose byte order is identified by * an optional byte-order mark */ public static final Charset UTF_16 = Charset.forName("UTF-16"); /** * 16-bit UTF (UCS Transformation Format) whose byte order is big-endian */ public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); /** * 16-bit UTF (UCS Transformation Format) whose byte order is little-endian */ public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); /** * 8-bit UTF (UCS Transformation Format) */ public static final Charset UTF_8 = Charset.forName("UTF-8"); /** * ISO Latin Alphabet No. 1, as known as ISO-LATIN-1 */ public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); /** * 7-bit ASCII, as known as ISO646-US or the Basic Latin block of the * Unicode character set */ public static final Charset US_ASCII = Charset.forName("US-ASCII"); private static final ThreadLocal> encoders = new ThreadLocal>() { @Override protected Map initialValue() { return new IdentityHashMap(); } }; private static final ThreadLocal> decoders = new ThreadLocal>() { @Override protected Map initialValue() { return new IdentityHashMap(); } }; /** * Returns a cached thread-local {@link CharsetEncoder} for the specified * charset. */ public static CharsetEncoder getEncoder(Charset charset) { if (charset == null) { throw new NullPointerException("charset"); } Map map = encoders.get(); CharsetEncoder e = map.get(charset); if (e != null) { e.reset(); e.onMalformedInput(CodingErrorAction.REPLACE); e.onUnmappableCharacter(CodingErrorAction.REPLACE); return e; } e = charset.newEncoder(); e.onMalformedInput(CodingErrorAction.REPLACE); e.onUnmappableCharacter(CodingErrorAction.REPLACE); map.put(charset, e); return e; } /** * Returns a cached thread-local {@link CharsetDecoder} for the specified * charset. */ public static CharsetDecoder getDecoder(Charset charset) { if (charset == null) { throw new NullPointerException("charset"); } Map map = decoders.get(); CharsetDecoder d = map.get(charset); if (d != null) { d.reset(); d.onMalformedInput(CodingErrorAction.REPLACE); d.onUnmappableCharacter(CodingErrorAction.REPLACE); return d; } d = charset.newDecoder(); d.onMalformedInput(CodingErrorAction.REPLACE); d.onUnmappableCharacter(CodingErrorAction.REPLACE); map.put(charset, d); return d; } private CharsetUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/DebugUtil.java000066400000000000000000000033671225554127700263140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelSink; import org.jboss.netty.util.internal.SystemPropertyUtil; /** * Determines if Netty is running in a debug mode or not. Please note that * this is not a Java debug mode. You can enable Netty debug mode by * specifying the {@code "org.jboss.netty.debug"} system property (e.g. * {@code java -Dorg.jboss.netty.debug ...}) *

* If debug mode is disabled (default), the stack trace of the exceptions are * compressed to help debugging a user application. *

* If debug mode is enabled, the stack trace of the exceptions raised in * {@link ChannelPipeline} or {@link ChannelSink} are retained as it is to help * debugging Netty. */ public final class DebugUtil { private static final boolean DEBUG_ENABLED = SystemPropertyUtil.getBoolean("org.jboss.netty.debug", false); /** * Returns {@code true} if and only if Netty debug mode is enabled. */ public static boolean isDebugEnabled() { return DEBUG_ENABLED; } private DebugUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/DefaultObjectSizeEstimator.java000066400000000000000000000077201225554127700316630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentMap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap; /** * The default {@link ObjectSizeEstimator} implementation for general purpose. */ public class DefaultObjectSizeEstimator implements ObjectSizeEstimator { private final ConcurrentMap, Integer> class2size = new ConcurrentIdentityWeakKeyHashMap, Integer>(); /** * Creates a new instance. */ public DefaultObjectSizeEstimator() { class2size.put(boolean.class, 4); // Probably an integer. class2size.put(byte.class, 1); class2size.put(char.class, 2); class2size.put(int.class, 4); class2size.put(short.class, 2); class2size.put(long.class, 8); class2size.put(float.class, 4); class2size.put(double.class, 8); class2size.put(void.class, 0); } public int estimateSize(Object o) { if (o == null) { return 8; } int answer = 8 + estimateSize(o.getClass(), null); if (o instanceof EstimatableObjectWrapper) { answer += estimateSize(((EstimatableObjectWrapper) o).unwrap()); } else if (o instanceof MessageEvent) { answer += estimateSize(((MessageEvent) o).getMessage()); } else if (o instanceof ChannelBuffer) { answer += ((ChannelBuffer) o).capacity(); } else if (o instanceof byte[]) { answer += ((byte[]) o).length; } else if (o instanceof ByteBuffer) { answer += ((ByteBuffer) o).remaining(); } else if (o instanceof CharSequence) { answer += ((CharSequence) o).length() << 1; } else if (o instanceof Iterable) { for (Object m : (Iterable) o) { answer += estimateSize(m); } } return align(answer); } private int estimateSize(Class clazz, Set> visitedClasses) { Integer objectSize = class2size.get(clazz); if (objectSize != null) { return objectSize; } if (visitedClasses != null) { if (visitedClasses.contains(clazz)) { return 0; } } else { visitedClasses = new HashSet>(); } visitedClasses.add(clazz); int answer = 8; // Basic overhead. for (Class c = clazz; c != null; c = c.getSuperclass()) { Field[] fields = c.getDeclaredFields(); for (Field f : fields) { if ((f.getModifiers() & Modifier.STATIC) != 0) { // Ignore static fields. continue; } answer += estimateSize(f.getType(), visitedClasses); } } visitedClasses.remove(clazz); // Some alignment. answer = align(answer); // Put the final answer. class2size.putIfAbsent(clazz, answer); return answer; } private static int align(int size) { int r = size % 8; if (r != 0) { size += 8 - r; } return size; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/EstimatableObjectWrapper.java000066400000000000000000000020701225554127700313400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; /** * Represents an object which contains another object that needs to be taken * into account by {@link ObjectSizeEstimator} for more accurate object size * estimation. */ public interface EstimatableObjectWrapper { /** * Returns the underlying object that needs to be taken into account * by {@link ObjectSizeEstimator} for more accurate object size estimation. */ Object unwrap(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/ExternalResourceReleasable.java000066400000000000000000000021121225554127700316650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; /** * A common interface for a class which depends on external resources that * need explicit release or shutdown. * @apiviz.landmark */ public interface ExternalResourceReleasable { /** * Releases the external resources that this object depends on. You should * not call this method if the external resources (e.g. thread pool) are * in use by other objects. */ void releaseExternalResources(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/ExternalResourceUtil.java000066400000000000000000000027441225554127700305560ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; /** * A utility class that provides the convenient shutdown of * {@link ExternalResourceReleasable}s. */ public final class ExternalResourceUtil { /** * Releases the specified {@link ExternalResourceReleasable}s. */ public static void release(ExternalResourceReleasable... releasables) { ExternalResourceReleasable[] releasablesCopy = new ExternalResourceReleasable[releasables.length]; for (int i = 0; i < releasables.length; i ++) { if (releasables[i] == null) { throw new NullPointerException("releasables[" + i + ']'); } releasablesCopy[i] = releasables[i]; } for (ExternalResourceReleasable e: releasablesCopy) { e.releaseExternalResources(); } } private ExternalResourceUtil() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/HashedWheelTimer.java000066400000000000000000000524651225554127700276150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.internal.ConcurrentIdentityHashMap; import org.jboss.netty.util.internal.DetectionUtil; import org.jboss.netty.util.internal.ReusableIterator; import org.jboss.netty.util.internal.SharedResourceMisuseDetector; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * A {@link Timer} optimized for approximated I/O timeout scheduling. * *

Tick Duration

* * As described with 'approximated', this timer does not execute the scheduled * {@link TimerTask} on time. {@link HashedWheelTimer}, on every tick, will * check if there are any {@link TimerTask}s behind the schedule and execute * them. *

* You can increase or decrease the accuracy of the execution timing by * specifying smaller or larger tick duration in the constructor. In most * network applications, I/O timeout does not need to be accurate. Therefore, * the default tick duration is 100 milliseconds and you will not need to try * different configurations in most cases. * *

Ticks per Wheel (Wheel Size)

* * {@link HashedWheelTimer} maintains a data structure called 'wheel'. * To put simply, a wheel is a hash table of {@link TimerTask}s whose hash * function is 'dead line of the task'. The default number of ticks per wheel * (i.e. the size of the wheel) is 512. You could specify a larger value * if you are going to schedule a lot of timeouts. * *

Do not create many instances.

* * {@link HashedWheelTimer} creates a new thread whenever it is instantiated and * started. Therefore, you should make sure to create only one instance and * share it across your application. One of the common mistakes, that makes * your application unresponsive, is to create a new instance in * {@link ChannelPipelineFactory}, which results in the creation of a new thread * for every connection. * *

Implementation Details

* * {@link HashedWheelTimer} is based on * George Varghese and * Tony Lauck's paper, * 'Hashed * and Hierarchical Timing Wheels: data structures to efficiently implement a * timer facility'. More comprehensive slides are located * here. */ public class HashedWheelTimer implements Timer { static final InternalLogger logger = InternalLoggerFactory.getInstance(HashedWheelTimer.class); private static final AtomicInteger id = new AtomicInteger(); private static final SharedResourceMisuseDetector misuseDetector = new SharedResourceMisuseDetector(HashedWheelTimer.class); private final Worker worker = new Worker(); final Thread workerThread; public static final int WORKER_STATE_INIT = 0; public static final int WORKER_STATE_STARTED = 1; public static final int WORKER_STATE_SHUTDOWN = 2; final AtomicInteger workerState = new AtomicInteger(); // 0 - init, 1 - started, 2 - shut down final long tickDuration; final Set[] wheel; final ReusableIterator[] iterators; final int mask; final ReadWriteLock lock = new ReentrantReadWriteLock(); final CountDownLatch startTimeInitialized = new CountDownLatch(1); volatile long startTime; volatile long tick; /** * Creates a new timer with the default thread factory * ({@link Executors#defaultThreadFactory()}), default tick duration, and * default number of ticks per wheel. */ public HashedWheelTimer() { this(Executors.defaultThreadFactory()); } /** * Creates a new timer with the default thread factory * ({@link Executors#defaultThreadFactory()}) and default number of ticks * per wheel. * * @param tickDuration the duration between tick * @param unit the time unit of the {@code tickDuration} */ public HashedWheelTimer(long tickDuration, TimeUnit unit) { this(Executors.defaultThreadFactory(), tickDuration, unit); } /** * Creates a new timer with the default thread factory * ({@link Executors#defaultThreadFactory()}). * * @param tickDuration the duration between tick * @param unit the time unit of the {@code tickDuration} * @param ticksPerWheel the size of the wheel */ public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) { this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel); } /** * Creates a new timer with the default tick duration and default number of * ticks per wheel. * * @param threadFactory a {@link ThreadFactory} that creates a * background {@link Thread} which is dedicated to * {@link TimerTask} execution. */ public HashedWheelTimer(ThreadFactory threadFactory) { this(threadFactory, 100, TimeUnit.MILLISECONDS); } /** * Creates a new timer with the default number of ticks per wheel. * * @param threadFactory a {@link ThreadFactory} that creates a * background {@link Thread} which is dedicated to * {@link TimerTask} execution. * @param tickDuration the duration between tick * @param unit the time unit of the {@code tickDuration} */ public HashedWheelTimer( ThreadFactory threadFactory, long tickDuration, TimeUnit unit) { this(threadFactory, tickDuration, unit, 512); } /** * Creates a new timer. * * @param threadFactory a {@link ThreadFactory} that creates a * background {@link Thread} which is dedicated to * {@link TimerTask} execution. * @param tickDuration the duration between tick * @param unit the time unit of the {@code tickDuration} * @param ticksPerWheel the size of the wheel */ public HashedWheelTimer( ThreadFactory threadFactory, long tickDuration, TimeUnit unit, int ticksPerWheel) { this(threadFactory, null, tickDuration, unit, ticksPerWheel); } /** * Creates a new timer. * * @param threadFactory a {@link ThreadFactory} that creates a * background {@link Thread} which is dedicated to * {@link TimerTask} execution. * @param determiner thread name determiner to control thread name. * @param tickDuration the duration between tick * @param unit the time unit of the {@code tickDuration} * @param ticksPerWheel the size of the wheel */ public HashedWheelTimer( ThreadFactory threadFactory, ThreadNameDeterminer determiner, long tickDuration, TimeUnit unit, int ticksPerWheel) { if (threadFactory == null) { throw new NullPointerException("threadFactory"); } if (unit == null) { throw new NullPointerException("unit"); } if (tickDuration <= 0) { throw new IllegalArgumentException( "tickDuration must be greater than 0: " + tickDuration); } if (ticksPerWheel <= 0) { throw new IllegalArgumentException( "ticksPerWheel must be greater than 0: " + ticksPerWheel); } // Normalize ticksPerWheel to power of two and initialize the wheel. wheel = createWheel(ticksPerWheel); iterators = createIterators(wheel); mask = wheel.length - 1; // Convert tickDuration to nanos. this.tickDuration = unit.toNanos(tickDuration); // Prevent overflow. if (this.tickDuration >= Long.MAX_VALUE / wheel.length) { throw new IllegalArgumentException(String.format( "tickDuration: %d (expected: 0 < tickDuration in nanos < %d", tickDuration, Long.MAX_VALUE / wheel.length)); } workerThread = threadFactory.newThread(new ThreadRenamingRunnable( worker, "Hashed wheel timer #" + id.incrementAndGet(), determiner)); // Misuse check misuseDetector.increase(); } @SuppressWarnings("unchecked") private static Set[] createWheel(int ticksPerWheel) { if (ticksPerWheel <= 0) { throw new IllegalArgumentException( "ticksPerWheel must be greater than 0: " + ticksPerWheel); } if (ticksPerWheel > 1073741824) { throw new IllegalArgumentException( "ticksPerWheel may not be greater than 2^30: " + ticksPerWheel); } ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel); Set[] wheel = new Set[ticksPerWheel]; for (int i = 0; i < wheel.length; i ++) { wheel[i] = new MapBackedSet( new ConcurrentIdentityHashMap(16, 0.95f, 4)); } return wheel; } @SuppressWarnings("unchecked") private static ReusableIterator[] createIterators(Set[] wheel) { ReusableIterator[] iterators = new ReusableIterator[wheel.length]; for (int i = 0; i < wheel.length; i ++) { iterators[i] = (ReusableIterator) wheel[i].iterator(); } return iterators; } private static int normalizeTicksPerWheel(int ticksPerWheel) { int normalizedTicksPerWheel = 1; while (normalizedTicksPerWheel < ticksPerWheel) { normalizedTicksPerWheel <<= 1; } return normalizedTicksPerWheel; } /** * Starts the background thread explicitly. The background thread will * start automatically on demand even if you did not call this method. * * @throws IllegalStateException if this timer has been * {@linkplain #stop() stopped} already */ public void start() { switch (workerState.get()) { case WORKER_STATE_INIT: if (workerState.compareAndSet(WORKER_STATE_INIT, WORKER_STATE_STARTED)) { workerThread.start(); } break; case WORKER_STATE_STARTED: break; case WORKER_STATE_SHUTDOWN: throw new IllegalStateException("cannot be started once stopped"); default: throw new Error("Invalid WorkerState"); } // Wait until the startTime is initialized by the worker. while (startTime == 0) { try { startTimeInitialized.await(); } catch (InterruptedException ignore) { // Ignore - it will be ready very soon. } } } public Set stop() { if (Thread.currentThread() == workerThread) { throw new IllegalStateException( HashedWheelTimer.class.getSimpleName() + ".stop() cannot be called from " + TimerTask.class.getSimpleName()); } if (!workerState.compareAndSet(WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) { // workerState can be 0 or 2 at this moment - let it always be 2. workerState.set(WORKER_STATE_SHUTDOWN); return Collections.emptySet(); } boolean interrupted = false; while (workerThread.isAlive()) { workerThread.interrupt(); try { workerThread.join(100); } catch (InterruptedException e) { interrupted = true; } } if (interrupted) { Thread.currentThread().interrupt(); } misuseDetector.decrease(); Set unprocessedTimeouts = new HashSet(); for (Set bucket: wheel) { unprocessedTimeouts.addAll(bucket); bucket.clear(); } return Collections.unmodifiableSet(unprocessedTimeouts); } public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { start(); if (task == null) { throw new NullPointerException("task"); } if (unit == null) { throw new NullPointerException("unit"); } long deadline = System.nanoTime() + unit.toNanos(delay) - startTime; // Add the timeout to the wheel. HashedWheelTimeout timeout; lock.readLock().lock(); try { timeout = new HashedWheelTimeout(task, deadline); if (workerState.get() == WORKER_STATE_SHUTDOWN) { throw new IllegalStateException("Cannot enqueue after shutdown"); } wheel[timeout.stopIndex].add(timeout); } finally { lock.readLock().unlock(); } return timeout; } private final class Worker implements Runnable { Worker() { } public void run() { // Initialize the startTime. startTime = System.nanoTime(); if (startTime == 0) { // We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized. startTime = 1; } // Notify the other threads waiting for the initialization at start(). startTimeInitialized.countDown(); List expiredTimeouts = new ArrayList(); do { final long deadline = waitForNextTick(); if (deadline > 0) { fetchExpiredTimeouts(expiredTimeouts, deadline); notifyExpiredTimeouts(expiredTimeouts); } } while (workerState.get() == WORKER_STATE_STARTED); } private void fetchExpiredTimeouts( List expiredTimeouts, long deadline) { // Find the expired timeouts and decrease the round counter // if necessary. Note that we don't send the notification // immediately to make sure the listeners are called without // an exclusive lock. lock.writeLock().lock(); try { ReusableIterator i = iterators[(int) (tick & mask)]; fetchExpiredTimeouts(expiredTimeouts, i, deadline); } finally { // Note that the tick is updated only while the writer lock is held, // so that newTimeout() and consequently new HashedWheelTimeout() never see an old value // while the reader lock is held. tick ++; lock.writeLock().unlock(); } } private void fetchExpiredTimeouts( List expiredTimeouts, ReusableIterator i, long deadline) { i.rewind(); while (i.hasNext()) { HashedWheelTimeout timeout = i.next(); if (timeout.remainingRounds <= 0) { i.remove(); if (timeout.deadline <= deadline) { expiredTimeouts.add(timeout); } else { // The timeout was placed into a wrong slot. This should never happen. throw new Error(String.format( "timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline)); } } else { timeout.remainingRounds --; } } } private void notifyExpiredTimeouts( List expiredTimeouts) { // Notify the expired timeouts. for (int i = expiredTimeouts.size() - 1; i >= 0; i --) { expiredTimeouts.get(i).expire(); } // Clean up the temporary list. expiredTimeouts.clear(); } /** * calculate goal nanoTime from startTime and current tick number, * then wait until that goal has been reached. * @return Long.MIN_VALUE if received a shutdown request, * current time otherwise (with Long.MIN_VALUE changed by +1) */ private long waitForNextTick() { long deadline = tickDuration * (tick + 1); for (;;) { final long currentTime = System.nanoTime() - startTime; long sleepTimeMs = (deadline - currentTime + 999999) / 1000000; if (sleepTimeMs <= 0) { if (currentTime == Long.MIN_VALUE) { return -Long.MAX_VALUE; } else { return currentTime; } } // Check if we run on windows, as if thats the case we will need // to round the sleepTime as workaround for a bug that only affect // the JVM if it runs on windows. // // See https://github.com/netty/netty/issues/356 if (DetectionUtil.isWindows()) { sleepTimeMs = sleepTimeMs / 10 * 10; } try { Thread.sleep(sleepTimeMs); } catch (InterruptedException e) { if (workerState.get() == WORKER_STATE_SHUTDOWN) { return Long.MIN_VALUE; } } } } } private final class HashedWheelTimeout implements Timeout { private static final int ST_INIT = 0; private static final int ST_CANCELLED = 1; private static final int ST_EXPIRED = 2; private final TimerTask task; final long deadline; final int stopIndex; volatile long remainingRounds; private final AtomicInteger state = new AtomicInteger(ST_INIT); HashedWheelTimeout(TimerTask task, long deadline) { this.task = task; this.deadline = deadline; long calculated = deadline / tickDuration; final long ticks = Math.max(calculated, tick); // Ensure we don't schedule for past. stopIndex = (int) (ticks & mask); remainingRounds = (calculated - tick) / wheel.length; } public Timer getTimer() { return HashedWheelTimer.this; } public TimerTask getTask() { return task; } public void cancel() { if (!state.compareAndSet(ST_INIT, ST_CANCELLED)) { // TODO return false return; } wheel[stopIndex].remove(this); } public boolean isCancelled() { return state.get() == ST_CANCELLED; } public boolean isExpired() { return state.get() != ST_INIT; } public void expire() { if (!state.compareAndSet(ST_INIT, ST_EXPIRED)) { return; } try { task.run(this); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn( "An exception was thrown by " + TimerTask.class.getSimpleName() + '.', t); } } } @Override public String toString() { final long currentTime = System.nanoTime(); long remaining = deadline - currentTime + startTime; StringBuilder buf = new StringBuilder(192); buf.append(getClass().getSimpleName()); buf.append('('); buf.append("deadline: "); if (remaining > 0) { buf.append(remaining); buf.append(" ns later"); } else if (remaining < 0) { buf.append(-remaining); buf.append(" ns ago"); } else { buf.append("now"); } if (isCancelled()) { buf.append(", cancelled"); } buf.append(", task: "); buf.append(getTask()); return buf.append(')').toString(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/MapBackedSet.java000066400000000000000000000032701225554127700267040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.io.Serializable; import java.util.AbstractSet; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * A {@link Map}-backed {@link Set}. */ final class MapBackedSet extends AbstractSet implements Serializable { private static final long serialVersionUID = -6761513279741915432L; private final Map map; /** * Creates a new instance which wraps the specified {@code map}. */ MapBackedSet(Map map) { this.map = map; } @Override public int size() { return map.size(); } @Override public boolean contains(Object o) { return map.containsKey(o); } @Override public boolean add(E o) { return map.put(o, Boolean.TRUE) == null; } @Override public boolean remove(Object o) { return map.remove(o) != null; } @Override public void clear() { map.clear(); } @Override public Iterator iterator() { return map.keySet().iterator(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/NetUtil.java000066400000000000000000000352311225554127700260070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.util.ArrayList; import java.util.StringTokenizer; /** * A class that holds a number of network-related constants. *

* This class borrowed some of its methods from a modified fork of the * Inet6Util class which was part of Apache Harmony. */ public final class NetUtil { /** * Creates an byte[] based on an ipAddressString. No error handling is * performed here. */ public static byte[] createByteArrayFromIpAddressString( String ipAddressString) { if (isValidIpV4Address(ipAddressString)) { StringTokenizer tokenizer = new StringTokenizer(ipAddressString, "."); String token; int tempInt; byte[] byteAddress = new byte[4]; for (int i = 0; i < 4; i++) { token = tokenizer.nextToken(); tempInt = Integer.parseInt(token); byteAddress[i] = (byte) tempInt; } return byteAddress; } if (isValidIpV6Address(ipAddressString)) { if (ipAddressString.charAt(0) == '[') { ipAddressString = ipAddressString.substring(1, ipAddressString .length() - 1); } StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ":.", true); ArrayList hexStrings = new ArrayList(); ArrayList decStrings = new ArrayList(); String token = ""; String prevToken = ""; int doubleColonIndex = -1; // If a double colon exists, we need to // insert 0s. // Go through the tokens, including the seperators ':' and '.' // When we hit a : or . the previous token will be added to either // the hex list or decimal list. In the case where we hit a :: // we will save the index of the hexStrings so we can add zeros // in to fill out the string while (tokenizer.hasMoreTokens()) { prevToken = token; token = tokenizer.nextToken(); if (":".equals(token)) { if (":".equals(prevToken)) { doubleColonIndex = hexStrings.size(); } else if (prevToken.length() > 0) { hexStrings.add(prevToken); } } else if (".".equals(token)) { decStrings.add(prevToken); } } if (":".equals(prevToken)) { if (":".equals(token)) { doubleColonIndex = hexStrings.size(); } else { hexStrings.add(token); } } else if (".".equals(prevToken)) { decStrings.add(token); } // figure out how many hexStrings we should have // also check if it is a IPv4 address int hexStringsLength = 8; // If we have an IPv4 address tagged on at the end, subtract // 4 bytes, or 2 hex words from the total if (!decStrings.isEmpty()) { hexStringsLength -= 2; } // if we hit a double Colon add the appropriate hex strings if (doubleColonIndex != -1) { int numberToInsert = hexStringsLength - hexStrings.size(); for (int i = 0; i < numberToInsert; i++) { hexStrings.add(doubleColonIndex, "0"); } } byte[] ipByteArray = new byte[16]; // Finally convert these strings to bytes... for (int i = 0; i < hexStrings.size(); i++) { convertToBytes(hexStrings.get(i), ipByteArray, i * 2); } // Now if there are any decimal values, we know where they go... for (int i = 0; i < decStrings.size(); i++) { ipByteArray[i + 12] = (byte) (Integer.parseInt(decStrings .get(i)) & 255); } return ipByteArray; } return null; } /** * Converts a 4 character hex word into a 2 byte word equivalent */ private static void convertToBytes(String hexWord, byte[] ipByteArray, int byteIndex) { int hexWordLength = hexWord.length(); int hexWordIndex = 0; ipByteArray[byteIndex] = 0; ipByteArray[byteIndex + 1] = 0; int charValue; // high order 4 bits of first byte if (hexWordLength > 3) { charValue = getIntValue(hexWord.charAt(hexWordIndex++)); ipByteArray[byteIndex] |= charValue << 4; } // low order 4 bits of the first byte if (hexWordLength > 2) { charValue = getIntValue(hexWord.charAt(hexWordIndex++)); ipByteArray[byteIndex] |= charValue; } // high order 4 bits of second byte if (hexWordLength > 1) { charValue = getIntValue(hexWord.charAt(hexWordIndex++)); ipByteArray[byteIndex + 1] |= charValue << 4; } // low order 4 bits of the first byte charValue = getIntValue(hexWord.charAt(hexWordIndex)); ipByteArray[byteIndex + 1] |= charValue & 15; } static int getIntValue(char c) { switch (c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; } c = Character.toLowerCase(c); switch (c) { case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; } return 0; } public static boolean isValidIpV6Address(String ipAddress) { int length = ipAddress.length(); boolean doubleColon = false; int numberOfColons = 0; int numberOfPeriods = 0; int numberOfPercent = 0; StringBuilder word = new StringBuilder(); char c = 0; char prevChar; int offset = 0; // offset for [] ip addresses if (length < 2) { return false; } for (int i = 0; i < length; i++) { prevChar = c; c = ipAddress.charAt(i); switch (c) { // case for an open bracket [x:x:x:...x] case '[': if (i != 0) { return false; // must be first character } if (ipAddress.charAt(length - 1) != ']') { return false; // must have a close ] } offset = 1; if (length < 4) { return false; } break; // case for a closed bracket at end of IP [x:x:x:...x] case ']': if (i != length - 1) { return false; // must be last charcter } if (ipAddress.charAt(0) != '[') { return false; // must have a open [ } break; // case for the last 32-bits represented as IPv4 x:x:x:x:x:x:d.d.d.d case '.': numberOfPeriods++; if (numberOfPeriods > 3) { return false; } if (!isValidIp4Word(word.toString())) { return false; } if (numberOfColons != 6 && !doubleColon) { return false; } // a special case ::1:2:3:4:5:d.d.d.d allows 7 colons with an // IPv4 ending, otherwise 7 :'s is bad if (numberOfColons == 7 && ipAddress.charAt(offset) != ':' && ipAddress.charAt(1 + offset) != ':') { return false; } word.delete(0, word.length()); break; case ':': // FIX "IP6 mechanism syntax #ip6-bad1" // An IPV6 address cannot start with a single ":". // Either it can starti with "::" or with a number. if (i == offset && (ipAddress.length() <= i || ipAddress.charAt(i + 1) != ':')) { return false; } // END FIX "IP6 mechanism syntax #ip6-bad1" numberOfColons++; if (numberOfColons > 7) { return false; } if (numberOfPeriods > 0) { return false; } if (prevChar == ':') { if (doubleColon) { return false; } doubleColon = true; } word.delete(0, word.length()); break; case '%': if (numberOfColons == 0) { return false; } numberOfPercent++; // validate that the stuff after the % is valid if (i + 1 >= length) { // in this case the percent is there but no number is // available return false; } try { Integer.parseInt(ipAddress.substring(i + 1)); } catch (NumberFormatException e) { // right now we just support an integer after the % so if // this is not // what is there then return return false; } break; default: if (numberOfPercent == 0) { if (word != null && word.length() > 3) { return false; } if (!isValidHexChar(c)) { return false; } } word.append(c); } } // Check if we have an IPv4 ending if (numberOfPeriods > 0) { // There is a test case with 7 colons and valid ipv4 this should resolve it if (numberOfPeriods != 3 || !(isValidIp4Word(word.toString()) && numberOfColons < 7)) { return false; } } else { // If we're at then end and we haven't had 7 colons then there is a // problem unless we encountered a doubleColon if (numberOfColons != 7 && !doubleColon) { return false; } // If we have an empty word at the end, it means we ended in either // a : or a . // If we did not end in :: then this is invalid if (numberOfPercent == 0) { if (word.length() == 0 && ipAddress.charAt(length - 1 - offset) == ':' && ipAddress.charAt(length - 2 - offset) != ':') { return false; } } } return true; } public static boolean isValidIp4Word(String word) { char c; if (word.length() < 1 || word.length() > 3) { return false; } for (int i = 0; i < word.length(); i++) { c = word.charAt(i); if (!(c >= '0' && c <= '9')) { return false; } } if (Integer.parseInt(word) > 255) { return false; } return true; } static boolean isValidHexChar(char c) { return c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'; } /** * Takes a string and parses it to see if it is a valid IPV4 address. * * @return true, if the string represents an IPV4 address in dotted * notation, false otherwise */ public static boolean isValidIpV4Address(String value) { int periods = 0; int i; int length = value.length(); if (length > 15) { return false; } char c; StringBuilder word = new StringBuilder(); for (i = 0; i < length; i++) { c = value.charAt(i); if (c == '.') { periods++; if (periods > 3) { return false; } if (word.length() == 0) { return false; } if (Integer.parseInt(word.toString()) > 255) { return false; } word.delete(0, word.length()); } else if (!Character.isDigit(c)) { return false; } else { if (word.length() > 2) { return false; } word.append(c); } } if (word.length() == 0 || Integer.parseInt(word.toString()) > 255) { return false; } if (periods != 3) { return false; } return true; } /** * A constructor to stop this class being constructed. */ private NetUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/ObjectSizeEstimator.java000066400000000000000000000020661225554127700303540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; /** * Estimates the size of an object in bytes. * * @apiviz.landmark * @apiviz.uses org.jboss.netty.util.EstimatableObjectWrapper */ public interface ObjectSizeEstimator { /** * Returns the estimated size of the specified object in bytes. * * @return a positive integer which represents the size of the specified * object in bytes */ int estimateSize(Object o); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/ThreadNameDeterminer.java000066400000000000000000000037061225554127700304540ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; /** * Overrides the thread name proposed by {@link ThreadRenamingRunnable}. */ public interface ThreadNameDeterminer { /** * {@link ThreadNameDeterminer} that accepts the proposed thread name * as is. */ ThreadNameDeterminer PROPOSED = new ThreadNameDeterminer() { public String determineThreadName(String currentThreadName, String proposedThreadName) throws Exception { return proposedThreadName; } }; /** * {@link ThreadNameDeterminer} that rejects the proposed thread name and * retains the current one. */ ThreadNameDeterminer CURRENT = new ThreadNameDeterminer() { public String determineThreadName(String currentThreadName, String proposedThreadName) throws Exception { return null; } }; /** * Overrides the thread name proposed by {@link ThreadRenamingRunnable}. * * @param currentThreadName the current thread name * @param proposedThreadName the proposed new thread name * @return the actual new thread name. * If {@code null} is returned, the proposed thread name is * discarded (i.e. no rename). */ String determineThreadName(String currentThreadName, String proposedThreadName) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/ThreadRenamingRunnable.java000066400000000000000000000120601225554127700307750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * A {@link Runnable} that changes the current thread name and reverts it back * when its execution ends. To change the default thread names set by Netty, * use {@link #setThreadNameDeterminer(ThreadNameDeterminer)}. * * @apiviz.landmark * @apiviz.has org.jboss.netty.util.ThreadNameDeterminer oneway - - */ public class ThreadRenamingRunnable implements Runnable { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ThreadRenamingRunnable.class); private static volatile ThreadNameDeterminer threadNameDeterminer = ThreadNameDeterminer.PROPOSED; private final ThreadNameDeterminer determiner; /** * Returns the {@link ThreadNameDeterminer} which overrides the proposed * new thread name. */ public static ThreadNameDeterminer getThreadNameDeterminer() { return threadNameDeterminer; } /** * Sets the {@link ThreadNameDeterminer} which overrides the proposed new * thread name. Please note that the specified {@link ThreadNameDeterminer} * affects only new {@link ThreadRenamingRunnable}s; the existing instances * are not affected at all. Therefore, you should make sure to call this * method at the earliest possible point (i.e. before any Netty worker * thread starts) for consistent thread naming. Otherwise, you might see * the default thread names and the new names appear at the same time in * the full thread dump. */ public static void setThreadNameDeterminer(ThreadNameDeterminer threadNameDeterminer) { if (threadNameDeterminer == null) { throw new NullPointerException("threadNameDeterminer"); } ThreadRenamingRunnable.threadNameDeterminer = threadNameDeterminer; } private final Runnable runnable; private final String proposedThreadName; /** * Creates a new instance which wraps the specified {@code runnable} * and changes the thread name to the specified thread name when the * specified {@code runnable} is running. */ public ThreadRenamingRunnable(Runnable runnable, String proposedThreadName, ThreadNameDeterminer determiner) { if (runnable == null) { throw new NullPointerException("runnable"); } if (proposedThreadName == null) { throw new NullPointerException("proposedThreadName"); } this.runnable = runnable; this.determiner = determiner; this.proposedThreadName = proposedThreadName; } public ThreadRenamingRunnable(Runnable runnable, String proposedThreadName) { this(runnable, proposedThreadName, null); } public void run() { final Thread currentThread = Thread.currentThread(); final String oldThreadName = currentThread.getName(); final String newThreadName = getNewThreadName(oldThreadName); // Change the thread name before starting the actual runnable. boolean renamed = false; if (!oldThreadName.equals(newThreadName)) { try { currentThread.setName(newThreadName); renamed = true; } catch (SecurityException e) { logger.debug( "Failed to rename a thread " + "due to security restriction.", e); } } // Run the actual runnable and revert the name back when it ends. try { runnable.run(); } finally { if (renamed) { // Revert the name back if the current thread was renamed. // We do not check the exception here because we know it works. currentThread.setName(oldThreadName); } } } private String getNewThreadName(String currentThreadName) { String newThreadName = null; try { ThreadNameDeterminer nameDeterminer = determiner; if (nameDeterminer == null) { nameDeterminer = getThreadNameDeterminer(); } newThreadName = nameDeterminer.determineThreadName( currentThreadName, proposedThreadName); } catch (Throwable t) { logger.warn("Failed to determine the thread name", t); } return newThreadName == null? currentThreadName : newThreadName; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/Timeout.java000066400000000000000000000027771225554127700260620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; /** * A handle associated with a {@link TimerTask} that is returned by a * {@link Timer}. */ public interface Timeout { /** * Returns the {@link Timer} that created this handle. */ Timer getTimer(); /** * Returns the {@link TimerTask} which is associated with this handle. */ TimerTask getTask(); /** * Returns {@code true} if and only if the {@link TimerTask} associated * with this handle has been expired. */ boolean isExpired(); /** * Returns {@code true} if and only if the {@link TimerTask} associated * with this handle has been cancelled. */ boolean isCancelled(); /** * Cancels the {@link TimerTask} associated with this handle. It the * task has been executed or cancelled already, it will return with no * side effect. */ void cancel(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/Timer.java000066400000000000000000000032331225554127700255000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Schedules {@link TimerTask}s for one-time future execution in a background * thread. * @apiviz.landmark * @apiviz.has org.jboss.netty.util.TimerTask oneway - - executes * @apiviz.has org.jboss.netty.util.Timeout oneway - - creates */ public interface Timer { /** * Schedules the specified {@link TimerTask} for one-time execution after * the specified delay. * * @return a handle which is associated with the specified task * * @throws IllegalStateException if this timer has been * {@linkplain #stop() stopped} already */ Timeout newTimeout(TimerTask task, long delay, TimeUnit unit); /** * Releases all resources acquired by this {@link Timer} and cancels all * tasks which were scheduled but not executed yet. * * @return the handles associated with the tasks which were canceled by * this method */ Set stop(); } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/TimerTask.java000066400000000000000000000021201225554127700263150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.util.concurrent.TimeUnit; /** * A task which is executed after the delay specified with * {@link Timer#newTimeout(TimerTask, long, TimeUnit)}. */ public interface TimerTask { /** * Executed after the delay specified with * {@link Timer#newTimeout(TimerTask, long, TimeUnit)}. * * @param timeout a handle which is associated with this task */ void run(Timeout timeout) throws Exception; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/VirtualExecutorService.java000066400000000000000000000137701225554127700311150ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; import java.util.Set; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * A delegating {@link ExecutorService} with its own termination management. *

* {@link VirtualExecutorService} is used when you want to inject an * {@link ExecutorService} but you do not want to allow the explicit termination * of threads on shutdown request. It is particularly useful when the * {@link ExecutorService} to inject is shared by different components and * the life cycle of the components depend on the termination of the injected * {@link ExecutorService}. * *

 * ExecutorService globalExecutor = ...;
 * ExecutorService virtualExecutor = new {@link VirtualExecutorService}(globalExecutor);
 *
 * {@link ChannelFactory} factory =
 *         new {@link NioServerSocketChannelFactory}(virtualExecutor, virtualExecutor);
 * ...
 *
 * // ChannelFactory.releaseExternalResources() shuts down the executor and
 * // interrupts the I/O threads to terminate all I/O tasks and to release all
 * // resources acquired by ChannelFactory.
 * factory.releaseExternalResources();
 *
 * // Note that globalExecutor is not shut down because VirtualExecutorService
 * // implements its own termination management. All threads which were acquired
 * // by ChannelFactory via VirtualExecutorService are returned to the pool.
 * assert !globalExecutor.isShutdown();
 * 
* *

The differences from an ordinary {@link ExecutorService}

* * A shutdown request ({@link #shutdown()} or {@link #shutdownNow()}) does not * shut down its parent {@link Executor} but simply sets its internal flag to * reject further execution request. *

* {@link #shutdownNow()} interrupts only the thread which is executing the * task executed via {@link VirtualExecutorService}. *

* {@link #awaitTermination(long, TimeUnit)} does not wait for real thread * termination but wait until {@link VirtualExecutorService} is shut down and * its active tasks are finished and the threads are returned to the parent * {@link Executor}. * @apiviz.landmark */ public class VirtualExecutorService extends AbstractExecutorService { private final Executor e; private final ExecutorService s; final Object startStopLock = new Object(); volatile boolean shutdown; final Set activeThreads = new MapBackedSet(new IdentityHashMap()); /** * Creates a new instance with the specified parent {@link Executor}. */ public VirtualExecutorService(Executor parent) { if (parent == null) { throw new NullPointerException("parent"); } if (parent instanceof ExecutorService) { e = null; s = (ExecutorService) parent; } else { e = parent; s = null; } } public boolean isShutdown() { synchronized (startStopLock) { return shutdown; } } public boolean isTerminated() { synchronized (startStopLock) { return shutdown && activeThreads.isEmpty(); } } public void shutdown() { synchronized (startStopLock) { if (shutdown) { return; } shutdown = true; } } public List shutdownNow() { synchronized (startStopLock) { if (!isTerminated()) { shutdown(); for (Thread t: activeThreads) { t.interrupt(); } } } return Collections.emptyList(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { synchronized (startStopLock) { if (!isTerminated()) { startStopLock.wait(TimeUnit.MILLISECONDS.convert(timeout, unit)); } return isTerminated(); } } public void execute(Runnable command) { if (command == null) { throw new NullPointerException("command"); } if (shutdown) { throw new RejectedExecutionException(); } if (s != null) { s.execute(new ChildExecutorRunnable(command)); } else { e.execute(new ChildExecutorRunnable(command)); } } private class ChildExecutorRunnable implements Runnable { private final Runnable runnable; ChildExecutorRunnable(Runnable runnable) { this.runnable = runnable; } public void run() { Thread thread = Thread.currentThread(); synchronized (startStopLock) { activeThreads.add(thread); } try { runnable.run(); } finally { synchronized (startStopLock) { boolean removed = activeThreads.remove(thread); assert removed; if (isTerminated()) { startStopLock.notifyAll(); } } } } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/000077500000000000000000000000001225554127700253705ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/AtomicFieldUpdaterUtil.java000066400000000000000000000044761225554127700326110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; final class AtomicFieldUpdaterUtil { private static final boolean AVAILABLE; static final class Node { volatile Node next; } static { boolean available = false; try { AtomicReferenceFieldUpdater tmp = AtomicReferenceFieldUpdater.newUpdater( Node.class, Node.class, "next"); // Test if AtomicReferenceFieldUpdater is really working. Node testNode = new Node(); tmp.set(testNode, testNode); if (testNode.next != testNode) { // Not set as expected - fall back to the safe mode. throw new Exception(); } available = true; } catch (Throwable t) { // Running in a restricted environment with a security manager. } AVAILABLE = available; } static AtomicReferenceFieldUpdater newRefUpdater(Class tclass, Class vclass, String fieldName) { if (AVAILABLE) { return AtomicReferenceFieldUpdater.newUpdater(tclass, vclass, fieldName); } else { return null; } } static AtomicIntegerFieldUpdater newIntUpdater(Class tclass, String fieldName) { if (AVAILABLE) { return AtomicIntegerFieldUpdater.newUpdater(tclass, fieldName); } else { return null; } } static boolean isAvailable() { return AVAILABLE; } private AtomicFieldUpdaterUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ByteBufferUtil.java000066400000000000000000000042201225554127700311240ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.lang.reflect.Method; import java.nio.ByteBuffer; /** * This is fork of ElasticSearch's ByteBufferAllocator.Cleaner class */ public final class ByteBufferUtil { private static final boolean CLEAN_SUPPORTED; private static final Method directBufferCleaner; private static final Method directBufferCleanerClean; static { Method directBufferCleanerX = null; Method directBufferCleanerCleanX = null; boolean v; try { directBufferCleanerX = Class.forName("java.nio.DirectByteBuffer").getMethod("cleaner"); directBufferCleanerX.setAccessible(true); directBufferCleanerCleanX = Class.forName("sun.misc.Cleaner").getMethod("clean"); directBufferCleanerCleanX.setAccessible(true); v = true; } catch (Exception e) { v = false; } CLEAN_SUPPORTED = v; directBufferCleaner = directBufferCleanerX; directBufferCleanerClean = directBufferCleanerCleanX; } /** * Destroy the given {@link ByteBuffer} if possible */ public static void destroy(ByteBuffer buffer) { if (CLEAN_SUPPORTED && buffer.isDirect()) { try { Object cleaner = directBufferCleaner.invoke(buffer); directBufferCleanerClean.invoke(cleaner); } catch (Exception e) { // silently ignore exception } } } private ByteBufferUtil() { // Utility class } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/CaseIgnoringComparator.java000066400000000000000000000023261225554127700326360ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.io.Serializable; import java.util.Comparator; public final class CaseIgnoringComparator implements Comparator, Serializable { private static final long serialVersionUID = 4582133183775373862L; public static final CaseIgnoringComparator INSTANCE = new CaseIgnoringComparator(); private CaseIgnoringComparator() { } public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } @SuppressWarnings("MethodMayBeStatic") private Object readResolve() { return INSTANCE; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ConcurrentHashMap.java000066400000000000000000001353611225554127700316300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.util.internal; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantLock; /** * An alternative {@link ConcurrentMap} implementation which is similar to * {@link java.util.concurrent.ConcurrentHashMap}. * @param the type of keys maintained by this map * @param the type of mapped values */ public final class ConcurrentHashMap extends AbstractMap implements ConcurrentMap { /** * The default initial capacity for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The default load factor for this table, used when not otherwise specified * in a constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The default concurrency level for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * The maximum number of segments to allow; used to bound constructor * arguments. */ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative /** * Number of unsynchronized retries in size and containsValue methods before * resorting to locking. This is used to avoid unbounded retries if tables * undergo continuous modification which would make it impossible to obtain * an accurate result. */ static final int RETRIES_BEFORE_LOCK = 2; /* ---------------- Fields -------------- */ /** * Mask value for indexing into segments. The upper bits of a key's hash * code are used to choose the segment. */ final int segmentMask; /** * Shift value for indexing within segments. */ final int segmentShift; /** * The segments, each of which is a specialized hash table */ final Segment[] segments; Set keySet; Set> entrySet; Collection values; /* ---------------- Small Utilities -------------- */ /** * Applies a supplemental hash function to a given hashCode, which defends * against poor quality hash functions. This is critical because * ConcurrentReferenceHashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ in lower * or upper bits. */ private static int hash(int h) { // Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += h << 15 ^ 0xffffcd7d; h ^= h >>> 10; h += h << 3; h ^= h >>> 6; h += (h << 2) + (h << 14); return h ^ h >>> 16; } /** * Returns the segment that should be used for key with given hash. * * @param hash the hash code for the key * @return the segment */ Segment segmentFor(int hash) { return segments[hash >>> segmentShift & segmentMask]; } private static int hashOf(Object key) { return hash(key.hashCode()); } /** * ConcurrentReferenceHashMap list entry. Note that this is never exported * out as a user-visible Map.Entry. * * Because the value field is volatile, not final, it is legal wrt * the Java Memory Model for an unsynchronized reader to see null * instead of initial value when read via a data race. Although a * reordering leading to this is not likely to ever actually * occur, the Segment.readValueUnderLock method is used as a * backup in case a null (pre-initialized) value is ever seen in * an unsynchronized access method. */ static final class HashEntry { final Object key; final int hash; volatile Object value; final HashEntry next; HashEntry( K key, int hash, HashEntry next, V value) { this.hash = hash; this.next = next; this.key = key; this.value = value; } @SuppressWarnings("unchecked") K key() { return (K) key; } @SuppressWarnings("unchecked") V value() { return (V) value; } void setValue(V value) { this.value = value; } @SuppressWarnings("unchecked") static HashEntry[] newArray(int i) { return new HashEntry[i]; } } /** * Segments are specialized versions of hash tables. This subclasses from * ReentrantLock opportunistically, just to simplify some locking and avoid * separate construction. */ static final class Segment extends ReentrantLock { /* * Segments maintain a table of entry lists that are ALWAYS kept in a * consistent state, so can be read without locking. Next fields of * nodes are immutable (final). All list additions are performed at the * front of each bin. This makes it easy to check changes, and also fast * to traverse. When nodes would otherwise be changed, new nodes are * created to replace them. This works well for hash tables since the * bin lists tend to be short. (The average length is less than two for * the default load factor threshold.) * * Read operations can thus proceed without locking, but rely on * selected uses of volatiles to ensure that completed write operations * performed by other threads are noticed. For most purposes, the * "count" field, tracking the number of elements, serves as that * volatile variable ensuring visibility. This is convenient because * this field needs to be read in many read operations anyway: * * - All (unsynchronized) read operations must first read the * "count" field, and should not look at table entries if * it is 0. * * - All (synchronized) write operations should write to * the "count" field after structurally changing any bin. * The operations must not take any action that could even * momentarily cause a concurrent read operation to see * inconsistent data. This is made easier by the nature of * the read operations in Map. For example, no operation * can reveal that the table has grown but the threshold * has not yet been updated, so there are no atomicity * requirements for this with respect to reads. * * As a guide, all critical volatile reads and writes to the count field * are marked in code comments. */ private static final long serialVersionUID = -2001752926705396395L; /** * The number of elements in this segment's region. */ transient volatile int count; /** * Number of updates that alter the size of the table. This is used * during bulk-read methods to make sure they see a consistent snapshot: * If modCounts change during a traversal of segments computing size or * checking containsValue, then we might have an inconsistent view of * state so (usually) must retry. */ int modCount; /** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always (capacity * loadFactor).) */ int threshold; /** * The per-segment table. */ transient volatile HashEntry[] table; /** * The load factor for the hash table. Even though this value is same * for all segments, it is replicated to avoid needing links to outer * object. */ final float loadFactor; Segment(int initialCapacity, float lf) { loadFactor = lf; setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") static Segment[] newArray(int i) { return new Segment[i]; } private static boolean keyEq(Object src, Object dest) { return src.equals(dest); } /** * Sets table to new HashEntry array. Call only while holding lock or in * constructor. */ void setTable(HashEntry[] newTable) { threshold = (int) (newTable.length * loadFactor); table = newTable; } /** * Returns properly casted first entry of bin for given hash. */ HashEntry getFirst(int hash) { HashEntry[] tab = table; return tab[hash & tab.length - 1]; } HashEntry newHashEntry( K key, int hash, HashEntry next, V value) { return new HashEntry(key, hash, next, value); } /** * Reads value field of an entry under lock. Called if value field ever * appears to be null. This is possible only if a compiler happens to * reorder a HashEntry initialization with its table assignment, which * is legal under memory model but is not known to ever occur. */ V readValueUnderLock(HashEntry e) { lock(); try { return e.value(); } finally { unlock(); } } /* Specialized implementations of map methods */ V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { V opaque = e.value(); if (opaque != null) { return opaque; } return readValueUnderLock(e); // recheck } e = e.next; } } return null; } boolean containsKey(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { return true; } e = e.next; } } return false; } boolean containsValue(Object value) { if (count != 0) { // read-volatile for (HashEntry e: table) { for (; e != null; e = e.next) { V opaque = e.value(); V v; if (opaque == null) { v = readValueUnderLock(e); // recheck } else { v = opaque; } if (value.equals(v)) { return true; } } } } return false; } boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } boolean replaced = false; if (e != null && oldValue.equals(e.value())) { replaced = true; e.setValue(newValue); } return replaced; } finally { unlock(); } } V replace(K key, int hash, V newValue) { lock(); try { HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { oldValue = e.value(); e.setValue(newValue); } return oldValue; } finally { unlock(); } } V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; if (c ++ > threshold) { // ensure capacity int reduced = rehash(); if (reduced > 0) { count = (c -= reduced) - 1; // write-volatile } } HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue; if (e != null) { oldValue = e.value(); if (!onlyIfAbsent) { e.setValue(value); } } else { oldValue = null; ++ modCount; tab[index] = newHashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } } int rehash() { HashEntry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) { return 0; } /* * Reclassify nodes in each list to new Map. Because we are using * power-of-two expansion, the elements from each bin must either * stay at same index, or move with a power of two offset. We * eliminate unnecessary node creation by catching cases where old * nodes can be reused because their next fields won't change. * Statistically, at the default threshold, only about one-sixth of * them need cloning when a table doubles. The nodes they replace * will be garbage collectable as soon as they are no longer * referenced by any reader thread that may be in the midst of * traversing table right now. */ HashEntry[] newTable = HashEntry.newArray(oldCapacity << 1); threshold = (int) (newTable.length * loadFactor); int sizeMask = newTable.length - 1; int reduce = 0; for (HashEntry e: oldTable) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. if (e != null) { HashEntry next = e.next; int idx = e.hash & sizeMask; // Single node on list if (next == null) { newTable[idx] = e; } else { // Reuse trailing consecutive sequence at same slot HashEntry lastRun = e; int lastIdx = idx; for (HashEntry last = next; last != null; last = last.next) { int k = last.hash & sizeMask; if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; // Clone all remaining nodes for (HashEntry p = e; p != lastRun; p = p.next) { // Skip GC'd weak references K key = p.key(); if (key == null) { reduce++; continue; } int k = p.hash & sizeMask; HashEntry n = newTable[k]; newTable[k] = newHashEntry(key, p.hash, n, p.value()); } } } } table = newTable; return reduce; } /** * Remove; match on key only if value null, else match both. */ V remove(Object key, int hash, Object value, boolean refRemove) { lock(); try { int c = count - 1; HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; // a reference remove operation compares the Reference instance while (e != null && key != e.key && (refRemove || hash != e.hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { V v = e.value(); if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay in list, // but all preceding ones need to be cloned. ++ modCount; HashEntry newFirst = e.next; for (HashEntry p = first; p != e; p = p.next) { K pKey = p.key(); if (pKey == null) { // Skip GC'd keys c --; continue; } newFirst = newHashEntry( pKey, p.hash, newFirst, p.value()); } tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } } void clear() { if (count != 0) { lock(); try { HashEntry[] tab = table; for (int i = 0; i < tab.length; i ++) { tab[i] = null; } ++ modCount; count = 0; // write-volatile } finally { unlock(); } } } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the specified initial capacity, load factor * and concurrency level. * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @param concurrencyLevel the estimated number of concurrently updating * threads. The implementation performs internal * sizing to try to accommodate this many threads. * @throws IllegalArgumentException if the initial capacity is negative or * the load factor or concurrencyLevel are * nonpositive. */ public ConcurrentHashMap( int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) { throw new IllegalArgumentException(); } if (concurrencyLevel > MAX_SEGMENTS) { concurrencyLevel = MAX_SEGMENTS; } // Find power-of-two sizes best matching arguments int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++ sshift; ssize <<= 1; } segmentShift = 32 - sshift; segmentMask = ssize - 1; segments = Segment.newArray(ssize); if (initialCapacity > MAXIMUM_CAPACITY) { initialCapacity = MAXIMUM_CAPACITY; } int c = initialCapacity / ssize; if (c * ssize < initialCapacity) { ++ c; } int cap = 1; while (cap < c) { cap <<= 1; } for (int i = 0; i < segments.length; ++ i) { segments[i] = new Segment(cap, loadFactor); } } /** * Creates a new, empty map with the specified initial capacity and load * factor and with the default reference types (weak keys, strong values), * and concurrencyLevel (16). * * @param initialCapacity The implementation performs internal sizing to * accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @throws IllegalArgumentException if the initial capacity of elements is * negative or the load factor is * nonpositive */ public ConcurrentHashMap(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with the specified initial capacity, and with * default reference types (weak keys, strong values), load factor (0.75) * and concurrencyLevel (16). * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of elements is * negative. */ public ConcurrentHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with a default initial capacity (16), reference * types (weak keys, strong values), default load factor (0.75) and * concurrencyLevel (16). */ public ConcurrentHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new map with the same mappings as the given map. The map is * created with a capacity of 1.5 times the number of mappings in the given * map or 16 (whichever is greater), and a default load factor (0.75) and * concurrencyLevel (16). * * @param m the map */ public ConcurrentHashMap(Map m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); putAll(m); } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings */ @Override public boolean isEmpty() { final Segment[] segments = this.segments; /* * We keep track of per-segment modCounts to avoid ABA problems in which * an element in one segment was added and in another removed during * traversal, in which case the table was never actually empty at any * point. Note the similar use of modCounts in the size() and * containsValue() methods, which are the only other methods also * susceptible to ABA problems. */ int[] mc = new int[segments.length]; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0) { return false; } else { mcsum += mc[i] = segments[i].modCount; } } // If mcsum happens to be zero, then we know we got a snapshot before // any modifications at all were made. This is probably common enough // to bother tracking. if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0 || mc[i] != segments[i].modCount) { return false; } } } return true; } /** * Returns the number of key-value mappings in this map. If the map contains * more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @return the number of key-value mappings in this map */ @Override public int size() { final Segment[] segments = this.segments; long sum = 0; long check = 0; int[] mc = new int[segments.length]; // Try a few times to get accurate count. On failure due to continuous // async changes in table, resort to locking. for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { check = 0; sum = 0; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { sum += segments[i].count; mcsum += mc[i] = segments[i].modCount; } if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { check += segments[i].count; if (mc[i] != segments[i].modCount) { check = -1; // force retry break; } } } if (check == sum) { break; } } if (check != sum) { // Resort to locking all segments sum = 0; for (Segment segment: segments) { segment.lock(); } for (Segment segment: segments) { sum += segment.count; } for (Segment segment: segments) { segment.unlock(); } } if (sum > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return (int) sum; } } /** * Returns the value to which the specified key is mapped, or {@code null} * if this map contains no mapping for the key. * *

More formally, if this map contains a mapping from a key {@code k} to * a value {@code v} such that {@code key.equals(k)}, then this method * returns {@code v}; otherwise it returns {@code null}. (There can be at * most one such mapping.) * * @throws NullPointerException if the specified key is null */ @Override public V get(Object key) { int hash = hashOf(key); return segmentFor(hash).get(key, hash); } /** * Tests if the specified object is a key in this table. * * @param key possible key * @return true if and only if the specified object is a key in * this table, as determined by the equals method; * false otherwise. * @throws NullPointerException if the specified key is null */ @Override public boolean containsKey(Object key) { int hash = hashOf(key); return segmentFor(hash).containsKey(key, hash); } /** * Returns true if this map maps one or more keys to the specified * value. Note: This method requires a full internal traversal of the hash * table, and so is much slower than method containsKey. * * @param value value whose presence in this map is to be tested * @return true if this map maps one or more keys to the specified * value * @throws NullPointerException if the specified value is null */ @Override public boolean containsValue(Object value) { if (value == null) { throw new NullPointerException(); } // See explanation of modCount use above final Segment[] segments = this.segments; int[] mc = new int[segments.length]; // Try a few times without locking for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { mcsum += mc[i] = segments[i].modCount; if (segments[i].containsValue(value)) { return true; } } boolean cleanSweep = true; if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (mc[i] != segments[i].modCount) { cleanSweep = false; break; } } } if (cleanSweep) { return false; } } // Resort to locking all segments for (Segment segment: segments) { segment.lock(); } boolean found = false; try { for (Segment segment: segments) { if (segment.containsValue(value)) { found = true; break; } } } finally { for (Segment segment: segments) { segment.unlock(); } } return found; } /** * Legacy method testing if some key maps into the specified value in this * table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure full compatibility * with class {@link Hashtable}, which supported this method prior to * introduction of the Java Collections framework. * * @param value a value to search for * @return true if and only if some key maps to the value * argument in this table as determined by the equals * method; false otherwise * @throws NullPointerException if the specified value is null */ public boolean contains(Object value) { return containsValue(value); } /** * Maps the specified key to the specified value in this table. Neither the * key nor the value can be null. * *

The value can be retrieved by calling the get method with a * key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key or value is null */ @Override public V put(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, false); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V putIfAbsent(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, true); } /** * Copies all of the mappings from the specified map to this one. These * mappings replace any mappings that this map had for any of the keys * currently in the specified map. * * @param m mappings to be stored in this map */ @Override public void putAll(Map m) { for (Map.Entry e: m.entrySet()) { put(e.getKey(), e.getValue()); } } /** * Removes the key (and its corresponding value) from this map. This method * does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key is null */ @Override public V remove(Object key) { int hash = hashOf(key); return segmentFor(hash).remove(key, hash, null, false); } /** * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { int hash = hashOf(key); if (value == null) { return false; } return segmentFor(hash).remove(key, hash, value, false) != null; } /** * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { if (oldValue == null || newValue == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, oldValue, newValue); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V replace(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, value); } /** * Removes all of the mappings from this map. */ @Override public void clear() { for (Segment segment: segments) { segment.clear(); } } /** * Returns a {@link Set} view of the keys contained in this map. The set is * backed by the map, so changes to the map are reflected in the set, and * vice-versa. The set supports element removal, which removes the * corresponding mapping from this map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set keySet() { Set ks = keySet; return ks != null? ks : (keySet = new KeySet()); } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are reflected * in the collection, and vice-versa. The collection supports element * removal, which removes the corresponding mapping from this map, via the * Iterator.remove, Collection.remove, removeAll, * retainAll, and clear operations. It does not support * the add or addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Collection values() { Collection vs = values; return vs != null? vs : (values = new Values()); } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are reflected in the * set, and vice-versa. The set supports element removal, which removes the * corresponding mapping from the map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set> entrySet() { Set> es = entrySet; return es != null? es : (entrySet = new EntrySet()); } /** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration keys() { return new KeyIterator(); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration elements() { return new ValueIterator(); } /* ---------------- Iterator Support -------------- */ abstract class HashIterator { int nextSegmentIndex; int nextTableIndex; HashEntry[] currentTable; HashEntry nextEntry; HashEntry lastReturned; K currentKey; // Strong reference to weak key (prevents gc) HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); } public void rewind() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; currentTable = null; nextEntry = null; lastReturned = null; currentKey = null; advance(); } public boolean hasMoreElements() { return hasNext(); } final void advance() { if (nextEntry != null && (nextEntry = nextEntry.next) != null) { return; } while (nextTableIndex >= 0) { if ((nextEntry = currentTable[nextTableIndex --]) != null) { return; } } while (nextSegmentIndex >= 0) { Segment seg = segments[nextSegmentIndex --]; if (seg.count != 0) { currentTable = seg.table; for (int j = currentTable.length - 1; j >= 0; -- j) { if ((nextEntry = currentTable[j]) != null) { nextTableIndex = j - 1; return; } } } } } public boolean hasNext() { while (nextEntry != null) { if (nextEntry.key() != null) { return true; } advance(); } return false; } HashEntry nextEntry() { do { if (nextEntry == null) { throw new NoSuchElementException(); } lastReturned = nextEntry; currentKey = lastReturned.key(); advance(); } while (currentKey == null); // Skip GC'd keys return lastReturned; } public void remove() { if (lastReturned == null) { throw new IllegalStateException(); } ConcurrentHashMap.this.remove(currentKey); lastReturned = null; } } final class KeyIterator extends HashIterator implements ReusableIterator, Enumeration { public K next() { return nextEntry().key(); } public K nextElement() { return nextEntry().key(); } } final class ValueIterator extends HashIterator implements ReusableIterator, Enumeration { public V next() { return nextEntry().value(); } public V nextElement() { return nextEntry().value(); } } /* * This class is needed for JDK5 compatibility. */ static class SimpleEntry implements Entry { private final K key; private V value; public SimpleEntry(K key, V value) { this.key = key; this.value = value; } public SimpleEntry(Entry entry) { key = entry.getKey(); value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } @SuppressWarnings("rawtypes") Map.Entry e = (Map.Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } @Override public int hashCode() { return (key == null? 0 : key.hashCode()) ^ (value == null? 0 : value.hashCode()); } @Override public String toString() { return key + "=" + value; } private static boolean eq(Object o1, Object o2) { return o1 == null? o2 == null : o1.equals(o2); } } /** * Custom Entry class used by EntryIterator.next(), that relays setValue * changes to the underlying map. */ final class WriteThroughEntry extends SimpleEntry { WriteThroughEntry(K k, V v) { super(k, v); } /** * Set our entry's value and write through to the map. The value to * return is somewhat arbitrary here. Since a WriteThroughEntry does not * necessarily track asynchronous changes, the most recent "previous" * value could be different from what we return (or could even have been * removed in which case the put will re-establish). We do not and can * not guarantee more. */ @Override public V setValue(V value) { if (value == null) { throw new NullPointerException(); } V v = super.setValue(value); put(getKey(), value); return v; } } final class EntryIterator extends HashIterator implements ReusableIterator> { public Map.Entry next() { HashEntry e = nextEntry(); return new WriteThroughEntry(e.key(), e.value()); } } final class KeySet extends AbstractSet { @Override public Iterator iterator() { return new KeyIterator(); } @Override public int size() { return ConcurrentHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object o) { return ConcurrentHashMap.this.remove(o) != null; } @Override public void clear() { ConcurrentHashMap.this.clear(); } } final class Values extends AbstractCollection { @Override public Iterator iterator() { return new ValueIterator(); } @Override public int size() { return ConcurrentHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsValue(o); } @Override public void clear() { ConcurrentHashMap.this.clear(); } } final class EntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new EntryIterator(); } @Override public boolean contains(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; V v = get(e.getKey()); return v != null && v.equals(e.getValue()); } @Override public boolean remove(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); } @Override public int size() { return ConcurrentHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentHashMap.this.isEmpty(); } @Override public void clear() { ConcurrentHashMap.this.clear(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ConcurrentIdentityHashMap.java000066400000000000000000001366751225554127700333530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.util.internal; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Arrays; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantLock; /** * An alternative identity-comparing {@link ConcurrentMap} which is similar to * {@link ConcurrentHashMap}. * @param the type of keys maintained by this map * @param the type of mapped values */ public final class ConcurrentIdentityHashMap extends AbstractMap implements ConcurrentMap { /** * The default initial capacity for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The default load factor for this table, used when not otherwise specified * in a constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The default concurrency level for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * The maximum number of segments to allow; used to bound constructor * arguments. */ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative /** * Number of unsynchronized retries in size and containsValue methods before * resorting to locking. This is used to avoid unbounded retries if tables * undergo continuous modification which would make it impossible to obtain * an accurate result. */ static final int RETRIES_BEFORE_LOCK = 2; /* ---------------- Fields -------------- */ /** * Mask value for indexing into segments. The upper bits of a key's hash * code are used to choose the segment. */ final int segmentMask; /** * Shift value for indexing within segments. */ final int segmentShift; /** * The segments, each of which is a specialized hash table */ final Segment[] segments; Set keySet; Set> entrySet; Collection values; /* ---------------- Small Utilities -------------- */ /** * Applies a supplemental hash function to a given hashCode, which defends * against poor quality hash functions. This is critical because * ConcurrentReferenceHashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ in lower * or upper bits. */ private static int hash(int h) { // Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += h << 15 ^ 0xffffcd7d; h ^= h >>> 10; h += h << 3; h ^= h >>> 6; h += (h << 2) + (h << 14); return h ^ h >>> 16; } /** * Returns the segment that should be used for key with given hash. * * @param hash the hash code for the key * @return the segment */ Segment segmentFor(int hash) { return segments[hash >>> segmentShift & segmentMask]; } private static int hashOf(Object key) { return hash(System.identityHashCode(key)); } /** * ConcurrentReferenceHashMap list entry. Note that this is never exported * out as a user-visible Map.Entry. * * Because the value field is volatile, not final, it is legal wrt * the Java Memory Model for an unsynchronized reader to see null * instead of initial value when read via a data race. Although a * reordering leading to this is not likely to ever actually * occur, the Segment.readValueUnderLock method is used as a * backup in case a null (pre-initialized) value is ever seen in * an unsynchronized access method. */ static final class HashEntry { final Object key; final int hash; volatile Object value; final HashEntry next; HashEntry( K key, int hash, HashEntry next, V value) { this.hash = hash; this.next = next; this.key = key; this.value = value; } @SuppressWarnings("unchecked") K key() { return (K) key; } @SuppressWarnings("unchecked") V value() { return (V) value; } void setValue(V value) { this.value = value; } @SuppressWarnings("unchecked") static HashEntry[] newArray(int i) { return new HashEntry[i]; } } /** * Segments are specialized versions of hash tables. This subclasses from * ReentrantLock opportunistically, just to simplify some locking and avoid * separate construction. */ static final class Segment extends ReentrantLock { /* * Segments maintain a table of entry lists that are ALWAYS kept in a * consistent state, so can be read without locking. Next fields of * nodes are immutable (final). All list additions are performed at the * front of each bin. This makes it easy to check changes, and also fast * to traverse. When nodes would otherwise be changed, new nodes are * created to replace them. This works well for hash tables since the * bin lists tend to be short. (The average length is less than two for * the default load factor threshold.) * * Read operations can thus proceed without locking, but rely on * selected uses of volatiles to ensure that completed write operations * performed by other threads are noticed. For most purposes, the * "count" field, tracking the number of elements, serves as that * volatile variable ensuring visibility. This is convenient because * this field needs to be read in many read operations anyway: * * - All (unsynchronized) read operations must first read the * "count" field, and should not look at table entries if * it is 0. * * - All (synchronized) write operations should write to * the "count" field after structurally changing any bin. * The operations must not take any action that could even * momentarily cause a concurrent read operation to see * inconsistent data. This is made easier by the nature of * the read operations in Map. For example, no operation * can reveal that the table has grown but the threshold * has not yet been updated, so there are no atomicity * requirements for this with respect to reads. * * As a guide, all critical volatile reads and writes to the count field * are marked in code comments. */ private static final long serialVersionUID = 5207829234977119743L; /** * The number of elements in this segment's region. */ transient volatile int count; /** * Number of updates that alter the size of the table. This is used * during bulk-read methods to make sure they see a consistent snapshot: * If modCounts change during a traversal of segments computing size or * checking containsValue, then we might have an inconsistent view of * state so (usually) must retry. */ int modCount; /** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always (capacity * loadFactor).) */ int threshold; /** * The per-segment table. */ transient volatile HashEntry[] table; /** * The load factor for the hash table. Even though this value is same * for all segments, it is replicated to avoid needing links to outer * object. */ final float loadFactor; Segment(int initialCapacity, float lf) { loadFactor = lf; setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") static Segment[] newArray(int i) { return new Segment[i]; } private static boolean keyEq(Object src, Object dest) { return src == dest; } /** * Sets table to new HashEntry array. Call only while holding lock or in * constructor. */ void setTable(HashEntry[] newTable) { threshold = (int) (newTable.length * loadFactor); table = newTable; } /** * Returns properly casted first entry of bin for given hash. */ HashEntry getFirst(int hash) { HashEntry[] tab = table; return tab[hash & tab.length - 1]; } HashEntry newHashEntry( K key, int hash, HashEntry next, V value) { return new HashEntry(key, hash, next, value); } /** * Reads value field of an entry under lock. Called if value field ever * appears to be null. This is possible only if a compiler happens to * reorder a HashEntry initialization with its table assignment, which * is legal under memory model but is not known to ever occur. */ V readValueUnderLock(HashEntry e) { lock(); try { return e.value(); } finally { unlock(); } } /* Specialized implementations of map methods */ V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry[] tab = table; HashEntry e = tab[hash & tab.length - 1]; if (tab != table) { return get(key, hash); } while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { V opaque = e.value(); if (opaque != null) { return opaque; } return readValueUnderLock(e); // recheck } e = e.next; } } return null; } boolean containsKey(Object key, int hash) { if (count != 0) { // read-volatile HashEntry[] tab = table; HashEntry e = tab[hash & tab.length - 1]; if (tab != table) { return containsKey(key, hash); } while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { return true; } e = e.next; } } return false; } boolean containsValue(Object value) { if (count != 0) { // read-volatile HashEntry[] tab = table; for (HashEntry e: tab) { for (; e != null; e = e.next) { V opaque = e.value(); V v; if (opaque == null) { v = readValueUnderLock(e); // recheck } else { v = opaque; } if (value.equals(v)) { return true; } } } if (table != tab) { return containsValue(value); } } return false; } boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } boolean replaced = false; if (e != null && oldValue.equals(e.value())) { replaced = true; e.setValue(newValue); } return replaced; } finally { unlock(); } } V replace(K key, int hash, V newValue) { lock(); try { HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { oldValue = e.value(); e.setValue(newValue); } return oldValue; } finally { unlock(); } } V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; if (c ++ > threshold) { // ensure capacity int reduced = rehash(); if (reduced > 0) { count = (c -= reduced) - 1; // write-volatile } } HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue; if (e != null) { oldValue = e.value(); if (!onlyIfAbsent) { e.setValue(value); } } else { oldValue = null; ++ modCount; tab[index] = newHashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } } int rehash() { HashEntry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) { return 0; } /* * Reclassify nodes in each list to new Map. Because we are using * power-of-two expansion, the elements from each bin must either * stay at same index, or move with a power of two offset. We * eliminate unnecessary node creation by catching cases where old * nodes can be reused because their next fields won't change. * Statistically, at the default threshold, only about one-sixth of * them need cloning when a table doubles. The nodes they replace * will be garbage collectable as soon as they are no longer * referenced by any reader thread that may be in the midst of * traversing table right now. */ HashEntry[] newTable = HashEntry.newArray(oldCapacity << 1); threshold = (int) (newTable.length * loadFactor); int sizeMask = newTable.length - 1; int reduce = 0; for (HashEntry e: oldTable) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. if (e != null) { HashEntry next = e.next; int idx = e.hash & sizeMask; // Single node on list if (next == null) { newTable[idx] = e; } else { // Reuse trailing consecutive sequence at same slot HashEntry lastRun = e; int lastIdx = idx; for (HashEntry last = next; last != null; last = last.next) { int k = last.hash & sizeMask; if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; // Clone all remaining nodes for (HashEntry p = e; p != lastRun; p = p.next) { // Skip GC'd weak references K key = p.key(); if (key == null) { reduce++; continue; } int k = p.hash & sizeMask; HashEntry n = newTable[k]; newTable[k] = newHashEntry(key, p.hash, n, p.value()); } } } } table = newTable; Arrays.fill(oldTable, null); return reduce; } /** * Remove; match on key only if value null, else match both. */ V remove(Object key, int hash, Object value, boolean refRemove) { lock(); try { int c = count - 1; HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; // a reference remove operation compares the Reference instance while (e != null && key != e.key && (refRemove || hash != e.hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { V v = e.value(); if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay in list, // but all preceding ones need to be cloned. ++ modCount; HashEntry newFirst = e.next; for (HashEntry p = first; p != e; p = p.next) { K pKey = p.key(); if (pKey == null) { // Skip GC'd keys c --; continue; } newFirst = newHashEntry( pKey, p.hash, newFirst, p.value()); } tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } } void clear() { if (count != 0) { lock(); try { HashEntry[] tab = table; for (int i = 0; i < tab.length; i ++) { tab[i] = null; } ++ modCount; count = 0; // write-volatile } finally { unlock(); } } } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the specified initial capacity, load factor * and concurrency level. * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @param concurrencyLevel the estimated number of concurrently updating * threads. The implementation performs internal * sizing to try to accommodate this many threads. * @throws IllegalArgumentException if the initial capacity is negative or * the load factor or concurrencyLevel are * nonpositive. */ public ConcurrentIdentityHashMap( int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) { throw new IllegalArgumentException(); } if (concurrencyLevel > MAX_SEGMENTS) { concurrencyLevel = MAX_SEGMENTS; } // Find power-of-two sizes best matching arguments int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++ sshift; ssize <<= 1; } segmentShift = 32 - sshift; segmentMask = ssize - 1; segments = Segment.newArray(ssize); if (initialCapacity > MAXIMUM_CAPACITY) { initialCapacity = MAXIMUM_CAPACITY; } int c = initialCapacity / ssize; if (c * ssize < initialCapacity) { ++ c; } int cap = 1; while (cap < c) { cap <<= 1; } for (int i = 0; i < segments.length; ++ i) { segments[i] = new Segment(cap, loadFactor); } } /** * Creates a new, empty map with the specified initial capacity and load * factor and with the default reference types (weak keys, strong values), * and concurrencyLevel (16). * * @param initialCapacity The implementation performs internal sizing to * accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @throws IllegalArgumentException if the initial capacity of elements is * negative or the load factor is * nonpositive */ public ConcurrentIdentityHashMap(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with the specified initial capacity, and with * default reference types (weak keys, strong values), load factor (0.75) * and concurrencyLevel (16). * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of elements is * negative. */ public ConcurrentIdentityHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with a default initial capacity (16), reference * types (weak keys, strong values), default load factor (0.75) and * concurrencyLevel (16). */ public ConcurrentIdentityHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new map with the same mappings as the given map. The map is * created with a capacity of 1.5 times the number of mappings in the given * map or 16 (whichever is greater), and a default load factor (0.75) and * concurrencyLevel (16). * * @param m the map */ public ConcurrentIdentityHashMap(Map m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); putAll(m); } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings */ @Override public boolean isEmpty() { final Segment[] segments = this.segments; /* * We keep track of per-segment modCounts to avoid ABA problems in which * an element in one segment was added and in another removed during * traversal, in which case the table was never actually empty at any * point. Note the similar use of modCounts in the size() and * containsValue() methods, which are the only other methods also * susceptible to ABA problems. */ int[] mc = new int[segments.length]; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0) { return false; } else { mcsum += mc[i] = segments[i].modCount; } } // If mcsum happens to be zero, then we know we got a snapshot before // any modifications at all were made. This is probably common enough // to bother tracking. if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0 || mc[i] != segments[i].modCount) { return false; } } } return true; } /** * Returns the number of key-value mappings in this map. If the map contains * more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @return the number of key-value mappings in this map */ @Override public int size() { final Segment[] segments = this.segments; long sum = 0; long check = 0; int[] mc = new int[segments.length]; // Try a few times to get accurate count. On failure due to continuous // async changes in table, resort to locking. for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { check = 0; sum = 0; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { sum += segments[i].count; mcsum += mc[i] = segments[i].modCount; } if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { check += segments[i].count; if (mc[i] != segments[i].modCount) { check = -1; // force retry break; } } } if (check == sum) { break; } } if (check != sum) { // Resort to locking all segments sum = 0; for (Segment segment: segments) { segment.lock(); } for (Segment segment: segments) { sum += segment.count; } for (Segment segment: segments) { segment.unlock(); } } if (sum > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return (int) sum; } } /** * Returns the value to which the specified key is mapped, or {@code null} * if this map contains no mapping for the key. * *

More formally, if this map contains a mapping from a key {@code k} to * a value {@code v} such that {@code key.equals(k)}, then this method * returns {@code v}; otherwise it returns {@code null}. (There can be at * most one such mapping.) * * @throws NullPointerException if the specified key is null */ @Override public V get(Object key) { int hash = hashOf(key); return segmentFor(hash).get(key, hash); } /** * Tests if the specified object is a key in this table. * * @param key possible key * @return true if and only if the specified object is a key in * this table, as determined by the equals method; * false otherwise. * @throws NullPointerException if the specified key is null */ @Override public boolean containsKey(Object key) { int hash = hashOf(key); return segmentFor(hash).containsKey(key, hash); } /** * Returns true if this map maps one or more keys to the specified * value. Note: This method requires a full internal traversal of the hash * table, and so is much slower than method containsKey. * * @param value value whose presence in this map is to be tested * @return true if this map maps one or more keys to the specified * value * @throws NullPointerException if the specified value is null */ @Override public boolean containsValue(Object value) { if (value == null) { throw new NullPointerException(); } // See explanation of modCount use above final Segment[] segments = this.segments; int[] mc = new int[segments.length]; // Try a few times without locking for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { mcsum += mc[i] = segments[i].modCount; if (segments[i].containsValue(value)) { return true; } } boolean cleanSweep = true; if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (mc[i] != segments[i].modCount) { cleanSweep = false; break; } } } if (cleanSweep) { return false; } } // Resort to locking all segments for (Segment segment: segments) { segment.lock(); } boolean found = false; try { for (Segment segment: segments) { if (segment.containsValue(value)) { found = true; break; } } } finally { for (Segment segment: segments) { segment.unlock(); } } return found; } /** * Legacy method testing if some key maps into the specified value in this * table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure full compatibility * with class {@link Hashtable}, which supported this method prior to * introduction of the Java Collections framework. * * @param value a value to search for * @return true if and only if some key maps to the value * argument in this table as determined by the equals * method; false otherwise * @throws NullPointerException if the specified value is null */ public boolean contains(Object value) { return containsValue(value); } /** * Maps the specified key to the specified value in this table. Neither the * key nor the value can be null. * *

The value can be retrieved by calling the get method with a * key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key or value is null */ @Override public V put(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, false); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V putIfAbsent(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, true); } /** * Copies all of the mappings from the specified map to this one. These * mappings replace any mappings that this map had for any of the keys * currently in the specified map. * * @param m mappings to be stored in this map */ @Override public void putAll(Map m) { for (Map.Entry e: m.entrySet()) { put(e.getKey(), e.getValue()); } } /** * Removes the key (and its corresponding value) from this map. This method * does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key is null */ @Override public V remove(Object key) { int hash = hashOf(key); return segmentFor(hash).remove(key, hash, null, false); } /** * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { int hash = hashOf(key); if (value == null) { return false; } return segmentFor(hash).remove(key, hash, value, false) != null; } /** * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { if (oldValue == null || newValue == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, oldValue, newValue); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V replace(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, value); } /** * Removes all of the mappings from this map. */ @Override public void clear() { for (Segment segment: segments) { segment.clear(); } } /** * Returns a {@link Set} view of the keys contained in this map. The set is * backed by the map, so changes to the map are reflected in the set, and * vice-versa. The set supports element removal, which removes the * corresponding mapping from this map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set keySet() { Set ks = keySet; return ks != null? ks : (keySet = new KeySet()); } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are reflected * in the collection, and vice-versa. The collection supports element * removal, which removes the corresponding mapping from this map, via the * Iterator.remove, Collection.remove, removeAll, * retainAll, and clear operations. It does not support * the add or addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Collection values() { Collection vs = values; return vs != null? vs : (values = new Values()); } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are reflected in the * set, and vice-versa. The set supports element removal, which removes the * corresponding mapping from the map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set> entrySet() { Set> es = entrySet; return es != null? es : (entrySet = new EntrySet()); } /** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration keys() { return new KeyIterator(); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration elements() { return new ValueIterator(); } /* ---------------- Iterator Support -------------- */ abstract class HashIterator { int nextSegmentIndex; int nextTableIndex; HashEntry[] currentTable; HashEntry nextEntry; HashEntry lastReturned; K currentKey; // Strong reference to weak key (prevents gc) HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); } public void rewind() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; currentTable = null; nextEntry = null; lastReturned = null; currentKey = null; advance(); } public boolean hasMoreElements() { return hasNext(); } final void advance() { if (nextEntry != null && (nextEntry = nextEntry.next) != null) { return; } while (nextTableIndex >= 0) { if ((nextEntry = currentTable[nextTableIndex --]) != null) { return; } } while (nextSegmentIndex >= 0) { Segment seg = segments[nextSegmentIndex --]; if (seg.count != 0) { currentTable = seg.table; for (int j = currentTable.length - 1; j >= 0; -- j) { if ((nextEntry = currentTable[j]) != null) { nextTableIndex = j - 1; return; } } } } } public boolean hasNext() { while (nextEntry != null) { if (nextEntry.key() != null) { return true; } advance(); } return false; } HashEntry nextEntry() { do { if (nextEntry == null) { throw new NoSuchElementException(); } lastReturned = nextEntry; currentKey = lastReturned.key(); advance(); } while (currentKey == null); // Skip GC'd keys return lastReturned; } public void remove() { if (lastReturned == null) { throw new IllegalStateException(); } ConcurrentIdentityHashMap.this.remove(currentKey); lastReturned = null; } } final class KeyIterator extends HashIterator implements ReusableIterator, Enumeration { public K next() { return nextEntry().key(); } public K nextElement() { return nextEntry().key(); } } final class ValueIterator extends HashIterator implements ReusableIterator, Enumeration { public V next() { return nextEntry().value(); } public V nextElement() { return nextEntry().value(); } } /* * This class is needed for JDK5 compatibility. */ static class SimpleEntry implements Entry { private final K key; private V value; public SimpleEntry(K key, V value) { this.key = key; this.value = value; } public SimpleEntry(Entry entry) { key = entry.getKey(); value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } @SuppressWarnings("rawtypes") Map.Entry e = (Map.Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } @Override public int hashCode() { return (key == null? 0 : key.hashCode()) ^ (value == null? 0 : value.hashCode()); } @Override public String toString() { return key + "=" + value; } private static boolean eq(Object o1, Object o2) { return o1 == null? o2 == null : o1.equals(o2); } } /** * Custom Entry class used by EntryIterator.next(), that relays setValue * changes to the underlying map. */ final class WriteThroughEntry extends SimpleEntry { WriteThroughEntry(K k, V v) { super(k, v); } /** * Set our entry's value and write through to the map. The value to * return is somewhat arbitrary here. Since a WriteThroughEntry does not * necessarily track asynchronous changes, the most recent "previous" * value could be different from what we return (or could even have been * removed in which case the put will re-establish). We do not and can * not guarantee more. */ @Override public V setValue(V value) { if (value == null) { throw new NullPointerException(); } V v = super.setValue(value); put(getKey(), value); return v; } } final class EntryIterator extends HashIterator implements ReusableIterator> { public Map.Entry next() { HashEntry e = nextEntry(); return new WriteThroughEntry(e.key(), e.value()); } } final class KeySet extends AbstractSet { @Override public Iterator iterator() { return new KeyIterator(); } @Override public int size() { return ConcurrentIdentityHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentIdentityHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object o) { return ConcurrentIdentityHashMap.this.remove(o) != null; } @Override public void clear() { ConcurrentIdentityHashMap.this.clear(); } } final class Values extends AbstractCollection { @Override public Iterator iterator() { return new ValueIterator(); } @Override public int size() { return ConcurrentIdentityHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentIdentityHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsValue(o); } @Override public void clear() { ConcurrentIdentityHashMap.this.clear(); } } final class EntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new EntryIterator(); } @Override public boolean contains(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; V v = get(e.getKey()); return v != null && v.equals(e.getValue()); } @Override public boolean remove(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; return ConcurrentIdentityHashMap.this.remove(e.getKey(), e.getValue()); } @Override public int size() { return ConcurrentIdentityHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentIdentityHashMap.this.isEmpty(); } @Override public void clear() { ConcurrentIdentityHashMap.this.clear(); } } } ConcurrentIdentityWeakKeyHashMap.java000066400000000000000000001435071225554127700345450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.util.internal; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantLock; /** * An alternative weak-key identity-comparing {@link ConcurrentMap} which is * similar to {@link ConcurrentHashMap}. * @param the type of keys maintained by this map * @param the type of mapped values */ public final class ConcurrentIdentityWeakKeyHashMap extends AbstractMap implements ConcurrentMap { /* * The basic strategy is to subdivide the table among Segments, * each of which itself is a concurrently readable hash table. */ /** * The default initial capacity for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The default load factor for this table, used when not otherwise specified * in a constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The default concurrency level for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * The maximum number of segments to allow; used to bound constructor * arguments. */ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative /** * Number of unsynchronized retries in size and containsValue methods before * resorting to locking. This is used to avoid unbounded retries if tables * undergo continuous modification which would make it impossible to obtain * an accurate result. */ static final int RETRIES_BEFORE_LOCK = 2; /* ---------------- Fields -------------- */ /** * Mask value for indexing into segments. The upper bits of a key's hash * code are used to choose the segment. */ final int segmentMask; /** * Shift value for indexing within segments. */ final int segmentShift; /** * The segments, each of which is a specialized hash table */ final Segment[] segments; Set keySet; Set> entrySet; Collection values; /* ---------------- Small Utilities -------------- */ /** * Applies a supplemental hash function to a given hashCode, which defends * against poor quality hash functions. This is critical because * ConcurrentReferenceHashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ in lower * or upper bits. */ private static int hash(int h) { // Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += h << 15 ^ 0xffffcd7d; h ^= h >>> 10; h += h << 3; h ^= h >>> 6; h += (h << 2) + (h << 14); return h ^ h >>> 16; } /** * Returns the segment that should be used for key with given hash. * * @param hash the hash code for the key * @return the segment */ Segment segmentFor(int hash) { return segments[hash >>> segmentShift & segmentMask]; } private static int hashOf(Object key) { return hash(System.identityHashCode(key)); } /* ---------------- Inner Classes -------------- */ /** * A weak-key reference which stores the key hash needed for reclamation. */ static final class WeakKeyReference extends WeakReference { final int hash; WeakKeyReference(K key, int hash, ReferenceQueue refQueue) { super(key, refQueue); this.hash = hash; } public int keyHash() { return hash; } public Object keyRef() { return this; } } /** * ConcurrentReferenceHashMap list entry. Note that this is never exported * out as a user-visible Map.Entry. * * Because the value field is volatile, not final, it is legal wrt * the Java Memory Model for an unsynchronized reader to see null * instead of initial value when read via a data race. Although a * reordering leading to this is not likely to ever actually * occur, the Segment.readValueUnderLock method is used as a * backup in case a null (pre-initialized) value is ever seen in * an unsynchronized access method. */ static final class HashEntry { final Object keyRef; final int hash; volatile Object valueRef; final HashEntry next; HashEntry( K key, int hash, HashEntry next, V value, ReferenceQueue refQueue) { this.hash = hash; this.next = next; keyRef = new WeakKeyReference(key, hash, refQueue); valueRef = value; } @SuppressWarnings("unchecked") K key() { return ((Reference) keyRef).get(); } V value() { return dereferenceValue(valueRef); } @SuppressWarnings("unchecked") V dereferenceValue(Object value) { if (value instanceof WeakKeyReference) { return ((Reference) value).get(); } return (V) value; } void setValue(V value) { valueRef = value; } @SuppressWarnings("unchecked") static HashEntry[] newArray(int i) { return new HashEntry[i]; } } /** * Segments are specialized versions of hash tables. This subclasses from * ReentrantLock opportunistically, just to simplify some locking and avoid * separate construction. */ static final class Segment extends ReentrantLock { /* * Segments maintain a table of entry lists that are ALWAYS kept in a * consistent state, so can be read without locking. Next fields of * nodes are immutable (final). All list additions are performed at the * front of each bin. This makes it easy to check changes, and also fast * to traverse. When nodes would otherwise be changed, new nodes are * created to replace them. This works well for hash tables since the * bin lists tend to be short. (The average length is less than two for * the default load factor threshold.) * * Read operations can thus proceed without locking, but rely on * selected uses of volatiles to ensure that completed write operations * performed by other threads are noticed. For most purposes, the * "count" field, tracking the number of elements, serves as that * volatile variable ensuring visibility. This is convenient because * this field needs to be read in many read operations anyway: * * - All (unsynchronized) read operations must first read the * "count" field, and should not look at table entries if * it is 0. * * - All (synchronized) write operations should write to * the "count" field after structurally changing any bin. * The operations must not take any action that could even * momentarily cause a concurrent read operation to see * inconsistent data. This is made easier by the nature of * the read operations in Map. For example, no operation * can reveal that the table has grown but the threshold * has not yet been updated, so there are no atomicity * requirements for this with respect to reads. * * As a guide, all critical volatile reads and writes to the count field * are marked in code comments. */ private static final long serialVersionUID = 5571906852696599096L; /** * The number of elements in this segment's region. */ transient volatile int count; /** * Number of updates that alter the size of the table. This is used * during bulk-read methods to make sure they see a consistent snapshot: * If modCounts change during a traversal of segments computing size or * checking containsValue, then we might have an inconsistent view of * state so (usually) must retry. */ int modCount; /** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always (capacity * loadFactor).) */ int threshold; /** * The per-segment table. */ transient volatile HashEntry[] table; /** * The load factor for the hash table. Even though this value is same * for all segments, it is replicated to avoid needing links to outer * object. */ final float loadFactor; /** * The collected weak-key reference queue for this segment. This should * be (re)initialized whenever table is assigned, */ transient volatile ReferenceQueue refQueue; Segment(int initialCapacity, float lf) { loadFactor = lf; setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") static Segment[] newArray(int i) { return new Segment[i]; } private static boolean keyEq(Object src, Object dest) { return src == dest; } /** * Sets table to new HashEntry array. Call only while holding lock or in * constructor. */ void setTable(HashEntry[] newTable) { threshold = (int) (newTable.length * loadFactor); table = newTable; refQueue = new ReferenceQueue(); } /** * Returns properly casted first entry of bin for given hash. */ HashEntry getFirst(int hash) { HashEntry[] tab = table; return tab[hash & tab.length - 1]; } HashEntry newHashEntry( K key, int hash, HashEntry next, V value) { return new HashEntry( key, hash, next, value, refQueue); } /** * Reads value field of an entry under lock. Called if value field ever * appears to be null. This is possible only if a compiler happens to * reorder a HashEntry initialization with its table assignment, which * is legal under memory model but is not known to ever occur. */ V readValueUnderLock(HashEntry e) { lock(); try { removeStale(); return e.value(); } finally { unlock(); } } /* Specialized implementations of map methods */ V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { Object opaque = e.valueRef; if (opaque != null) { return e.dereferenceValue(opaque); } return readValueUnderLock(e); // recheck } e = e.next; } } return null; } boolean containsKey(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { return true; } e = e.next; } } return false; } boolean containsValue(Object value) { if (count != 0) { // read-volatile for (HashEntry e: table) { for (; e != null; e = e.next) { Object opaque = e.valueRef; V v; if (opaque == null) { v = readValueUnderLock(e); // recheck } else { v = e.dereferenceValue(opaque); } if (value.equals(v)) { return true; } } } } return false; } boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { removeStale(); HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } boolean replaced = false; if (e != null && oldValue.equals(e.value())) { replaced = true; e.setValue(newValue); } return replaced; } finally { unlock(); } } V replace(K key, int hash, V newValue) { lock(); try { removeStale(); HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { oldValue = e.value(); e.setValue(newValue); } return oldValue; } finally { unlock(); } } V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { removeStale(); int c = count; if (c ++ > threshold) { // ensure capacity int reduced = rehash(); if (reduced > 0) { count = (c -= reduced) - 1; // write-volatile } } HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue; if (e != null) { oldValue = e.value(); if (!onlyIfAbsent) { e.setValue(value); } } else { oldValue = null; ++ modCount; tab[index] = newHashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } } int rehash() { HashEntry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) { return 0; } /* * Reclassify nodes in each list to new Map. Because we are using * power-of-two expansion, the elements from each bin must either * stay at same index, or move with a power of two offset. We * eliminate unnecessary node creation by catching cases where old * nodes can be reused because their next fields won't change. * Statistically, at the default threshold, only about one-sixth of * them need cloning when a table doubles. The nodes they replace * will be garbage collectable as soon as they are no longer * referenced by any reader thread that may be in the midst of * traversing table right now. */ HashEntry[] newTable = HashEntry.newArray(oldCapacity << 1); threshold = (int) (newTable.length * loadFactor); int sizeMask = newTable.length - 1; int reduce = 0; for (HashEntry e: oldTable) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. if (e != null) { HashEntry next = e.next; int idx = e.hash & sizeMask; // Single node on list if (next == null) { newTable[idx] = e; } else { // Reuse trailing consecutive sequence at same slot HashEntry lastRun = e; int lastIdx = idx; for (HashEntry last = next; last != null; last = last.next) { int k = last.hash & sizeMask; if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; // Clone all remaining nodes for (HashEntry p = e; p != lastRun; p = p.next) { // Skip GC'd weak references K key = p.key(); if (key == null) { reduce++; continue; } int k = p.hash & sizeMask; HashEntry n = newTable[k]; newTable[k] = newHashEntry(key, p.hash, n, p.value()); } } } } table = newTable; return reduce; } /** * Remove; match on key only if value null, else match both. */ V remove(Object key, int hash, Object value, boolean refRemove) { lock(); try { if (!refRemove) { removeStale(); } int c = count - 1; HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; // a reference remove operation compares the Reference instance while (e != null && key != e.keyRef && (refRemove || hash != e.hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { V v = e.value(); if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay in list, // but all preceding ones need to be cloned. ++ modCount; HashEntry newFirst = e.next; for (HashEntry p = first; p != e; p = p.next) { K pKey = p.key(); if (pKey == null) { // Skip GC'd keys c --; continue; } newFirst = newHashEntry( pKey, p.hash, newFirst, p.value()); } tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } } @SuppressWarnings("rawtypes") void removeStale() { WeakKeyReference ref; while ((ref = (WeakKeyReference) refQueue.poll()) != null) { remove(ref.keyRef(), ref.keyHash(), null, true); } } void clear() { if (count != 0) { lock(); try { HashEntry[] tab = table; for (int i = 0; i < tab.length; i ++) { tab[i] = null; } ++ modCount; // replace the reference queue to avoid unnecessary stale // cleanups refQueue = new ReferenceQueue(); count = 0; // write-volatile } finally { unlock(); } } } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the specified initial capacity, load factor * and concurrency level. * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @param concurrencyLevel the estimated number of concurrently updating * threads. The implementation performs internal * sizing to try to accommodate this many threads. * @throws IllegalArgumentException if the initial capacity is negative or * the load factor or concurrencyLevel are * nonpositive. */ public ConcurrentIdentityWeakKeyHashMap( int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) { throw new IllegalArgumentException(); } if (concurrencyLevel > MAX_SEGMENTS) { concurrencyLevel = MAX_SEGMENTS; } // Find power-of-two sizes best matching arguments int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++ sshift; ssize <<= 1; } segmentShift = 32 - sshift; segmentMask = ssize - 1; segments = Segment.newArray(ssize); if (initialCapacity > MAXIMUM_CAPACITY) { initialCapacity = MAXIMUM_CAPACITY; } int c = initialCapacity / ssize; if (c * ssize < initialCapacity) { ++ c; } int cap = 1; while (cap < c) { cap <<= 1; } for (int i = 0; i < segments.length; ++ i) { segments[i] = new Segment(cap, loadFactor); } } /** * Creates a new, empty map with the specified initial capacity and load * factor and with the default reference types (weak keys, strong values), * and concurrencyLevel (16). * * @param initialCapacity The implementation performs internal sizing to * accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @throws IllegalArgumentException if the initial capacity of elements is * negative or the load factor is * nonpositive */ public ConcurrentIdentityWeakKeyHashMap(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with the specified initial capacity, and with * default reference types (weak keys, strong values), load factor (0.75) * and concurrencyLevel (16). * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of elements is * negative. */ public ConcurrentIdentityWeakKeyHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with a default initial capacity (16), reference * types (weak keys, strong values), default load factor (0.75) and * concurrencyLevel (16). */ public ConcurrentIdentityWeakKeyHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new map with the same mappings as the given map. The map is * created with a capacity of 1.5 times the number of mappings in the given * map or 16 (whichever is greater), and a default load factor (0.75) and * concurrencyLevel (16). * * @param m the map */ public ConcurrentIdentityWeakKeyHashMap(Map m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); putAll(m); } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings */ @Override public boolean isEmpty() { final Segment[] segments = this.segments; /* * We keep track of per-segment modCounts to avoid ABA problems in which * an element in one segment was added and in another removed during * traversal, in which case the table was never actually empty at any * point. Note the similar use of modCounts in the size() and * containsValue() methods, which are the only other methods also * susceptible to ABA problems. */ int[] mc = new int[segments.length]; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0) { return false; } else { mcsum += mc[i] = segments[i].modCount; } } // If mcsum happens to be zero, then we know we got a snapshot before // any modifications at all were made. This is probably common enough // to bother tracking. if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0 || mc[i] != segments[i].modCount) { return false; } } } return true; } /** * Returns the number of key-value mappings in this map. If the map contains * more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @return the number of key-value mappings in this map */ @Override public int size() { final Segment[] segments = this.segments; long sum = 0; long check = 0; int[] mc = new int[segments.length]; // Try a few times to get accurate count. On failure due to continuous // async changes in table, resort to locking. for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { check = 0; sum = 0; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { sum += segments[i].count; mcsum += mc[i] = segments[i].modCount; } if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { check += segments[i].count; if (mc[i] != segments[i].modCount) { check = -1; // force retry break; } } } if (check == sum) { break; } } if (check != sum) { // Resort to locking all segments sum = 0; for (Segment segment: segments) { segment.lock(); } for (Segment segment: segments) { sum += segment.count; } for (Segment segment: segments) { segment.unlock(); } } if (sum > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return (int) sum; } } /** * Returns the value to which the specified key is mapped, or {@code null} * if this map contains no mapping for the key. * *

More formally, if this map contains a mapping from a key {@code k} to * a value {@code v} such that {@code key.equals(k)}, then this method * returns {@code v}; otherwise it returns {@code null}. (There can be at * most one such mapping.) * * @throws NullPointerException if the specified key is null */ @Override public V get(Object key) { int hash = hashOf(key); return segmentFor(hash).get(key, hash); } /** * Tests if the specified object is a key in this table. * * @param key possible key * @return true if and only if the specified object is a key in * this table, as determined by the equals method; * false otherwise. * @throws NullPointerException if the specified key is null */ @Override public boolean containsKey(Object key) { int hash = hashOf(key); return segmentFor(hash).containsKey(key, hash); } /** * Returns true if this map maps one or more keys to the specified * value. Note: This method requires a full internal traversal of the hash * table, and so is much slower than method containsKey. * * @param value value whose presence in this map is to be tested * @return true if this map maps one or more keys to the specified * value * @throws NullPointerException if the specified value is null */ @Override public boolean containsValue(Object value) { if (value == null) { throw new NullPointerException(); } // See explanation of modCount use above final Segment[] segments = this.segments; int[] mc = new int[segments.length]; // Try a few times without locking for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { mcsum += mc[i] = segments[i].modCount; if (segments[i].containsValue(value)) { return true; } } boolean cleanSweep = true; if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (mc[i] != segments[i].modCount) { cleanSweep = false; break; } } } if (cleanSweep) { return false; } } // Resort to locking all segments for (Segment segment: segments) { segment.lock(); } boolean found = false; try { for (Segment segment: segments) { if (segment.containsValue(value)) { found = true; break; } } } finally { for (Segment segment: segments) { segment.unlock(); } } return found; } /** * Legacy method testing if some key maps into the specified value in this * table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure full compatibility * with class {@link Hashtable}, which supported this method prior to * introduction of the Java Collections framework. * * @param value a value to search for * @return true if and only if some key maps to the value * argument in this table as determined by the equals * method; false otherwise * @throws NullPointerException if the specified value is null */ public boolean contains(Object value) { return containsValue(value); } /** * Maps the specified key to the specified value in this table. Neither the * key nor the value can be null. * *

The value can be retrieved by calling the get method with a * key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key or value is null */ @Override public V put(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, false); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V putIfAbsent(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, true); } /** * Copies all of the mappings from the specified map to this one. These * mappings replace any mappings that this map had for any of the keys * currently in the specified map. * * @param m mappings to be stored in this map */ @Override public void putAll(Map m) { for (Map.Entry e: m.entrySet()) { put(e.getKey(), e.getValue()); } } /** * Removes the key (and its corresponding value) from this map. This method * does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key is null */ @Override public V remove(Object key) { int hash = hashOf(key); return segmentFor(hash).remove(key, hash, null, false); } /** * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { int hash = hashOf(key); if (value == null) { return false; } return segmentFor(hash).remove(key, hash, value, false) != null; } /** * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { if (oldValue == null || newValue == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, oldValue, newValue); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V replace(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, value); } /** * Removes all of the mappings from this map. */ @Override public void clear() { for (Segment segment: segments) { segment.clear(); } } /** * Removes any stale entries whose keys have been finalized. Use of this * method is normally not necessary since stale entries are automatically * removed lazily, when blocking operations are required. However, there are * some cases where this operation should be performed eagerly, such as * cleaning up old references to a ClassLoader in a multi-classloader * environment. * * Note: this method will acquire locks, one at a time, across all segments * of this table, so if it is to be used, it should be used sparingly. */ public void purgeStaleEntries() { for (Segment segment: segments) { segment.removeStale(); } } /** * Returns a {@link Set} view of the keys contained in this map. The set is * backed by the map, so changes to the map are reflected in the set, and * vice-versa. The set supports element removal, which removes the * corresponding mapping from this map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set keySet() { Set ks = keySet; return ks != null? ks : (keySet = new KeySet()); } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are reflected * in the collection, and vice-versa. The collection supports element * removal, which removes the corresponding mapping from this map, via the * Iterator.remove, Collection.remove, removeAll, * retainAll, and clear operations. It does not support * the add or addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Collection values() { Collection vs = values; return vs != null? vs : (values = new Values()); } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are reflected in the * set, and vice-versa. The set supports element removal, which removes the * corresponding mapping from the map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set> entrySet() { Set> es = entrySet; return es != null? es : (entrySet = new EntrySet()); } /** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration keys() { return new KeyIterator(); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration elements() { return new ValueIterator(); } /* ---------------- Iterator Support -------------- */ abstract class HashIterator { int nextSegmentIndex; int nextTableIndex; HashEntry[] currentTable; HashEntry nextEntry; HashEntry lastReturned; K currentKey; // Strong reference to weak key (prevents gc) HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); } public void rewind() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; currentTable = null; nextEntry = null; lastReturned = null; currentKey = null; advance(); } public boolean hasMoreElements() { return hasNext(); } final void advance() { if (nextEntry != null && (nextEntry = nextEntry.next) != null) { return; } while (nextTableIndex >= 0) { if ((nextEntry = currentTable[nextTableIndex --]) != null) { return; } } while (nextSegmentIndex >= 0) { Segment seg = segments[nextSegmentIndex --]; if (seg.count != 0) { currentTable = seg.table; for (int j = currentTable.length - 1; j >= 0; -- j) { if ((nextEntry = currentTable[j]) != null) { nextTableIndex = j - 1; return; } } } } } public boolean hasNext() { while (nextEntry != null) { if (nextEntry.key() != null) { return true; } advance(); } return false; } HashEntry nextEntry() { do { if (nextEntry == null) { throw new NoSuchElementException(); } lastReturned = nextEntry; currentKey = lastReturned.key(); advance(); } while (currentKey == null); // Skip GC'd keys return lastReturned; } public void remove() { if (lastReturned == null) { throw new IllegalStateException(); } ConcurrentIdentityWeakKeyHashMap.this.remove(currentKey); lastReturned = null; } } final class KeyIterator extends HashIterator implements ReusableIterator, Enumeration { public K next() { return nextEntry().key(); } public K nextElement() { return nextEntry().key(); } } final class ValueIterator extends HashIterator implements ReusableIterator, Enumeration { public V next() { return nextEntry().value(); } public V nextElement() { return nextEntry().value(); } } /* * This class is needed for JDK5 compatibility. */ static class SimpleEntry implements Entry { private final K key; private V value; public SimpleEntry(K key, V value) { this.key = key; this.value = value; } public SimpleEntry(Entry entry) { key = entry.getKey(); value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } @SuppressWarnings("rawtypes") Map.Entry e = (Map.Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } @Override public int hashCode() { return (key == null? 0 : key.hashCode()) ^ (value == null? 0 : value.hashCode()); } @Override public String toString() { return key + "=" + value; } private static boolean eq(Object o1, Object o2) { return o1 == null? o2 == null : o1.equals(o2); } } /** * Custom Entry class used by EntryIterator.next(), that relays setValue * changes to the underlying map. */ final class WriteThroughEntry extends SimpleEntry { WriteThroughEntry(K k, V v) { super(k, v); } /** * Set our entry's value and write through to the map. The value to * return is somewhat arbitrary here. Since a WriteThroughEntry does not * necessarily track asynchronous changes, the most recent "previous" * value could be different from what we return (or could even have been * removed in which case the put will re-establish). We do not and can * not guarantee more. */ @Override public V setValue(V value) { if (value == null) { throw new NullPointerException(); } V v = super.setValue(value); put(getKey(), value); return v; } } final class EntryIterator extends HashIterator implements ReusableIterator> { public Map.Entry next() { HashEntry e = nextEntry(); return new WriteThroughEntry(e.key(), e.value()); } } final class KeySet extends AbstractSet { @Override public Iterator iterator() { return new KeyIterator(); } @Override public int size() { return ConcurrentIdentityWeakKeyHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentIdentityWeakKeyHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object o) { return ConcurrentIdentityWeakKeyHashMap.this.remove(o) != null; } @Override public void clear() { ConcurrentIdentityWeakKeyHashMap.this.clear(); } } final class Values extends AbstractCollection { @Override public Iterator iterator() { return new ValueIterator(); } @Override public int size() { return ConcurrentIdentityWeakKeyHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentIdentityWeakKeyHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsValue(o); } @Override public void clear() { ConcurrentIdentityWeakKeyHashMap.this.clear(); } } final class EntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new EntryIterator(); } @Override public boolean contains(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; V v = get(e.getKey()); return v != null && v.equals(e.getValue()); } @Override public boolean remove(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; return ConcurrentIdentityWeakKeyHashMap.this.remove(e.getKey(), e.getValue()); } @Override public int size() { return ConcurrentIdentityWeakKeyHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentIdentityWeakKeyHashMap.this.isEmpty(); } @Override public void clear() { ConcurrentIdentityWeakKeyHashMap.this.clear(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ConcurrentWeakKeyHashMap.java000066400000000000000000001432341225554127700331070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.util.internal; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantLock; /** * An alternative weak-key {@link ConcurrentMap} which is similar to * {@link ConcurrentHashMap}. * @param the type of keys maintained by this map * @param the type of mapped values */ public final class ConcurrentWeakKeyHashMap extends AbstractMap implements ConcurrentMap { /* * The basic strategy is to subdivide the table among Segments, * each of which itself is a concurrently readable hash table. */ /** * The default initial capacity for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The default load factor for this table, used when not otherwise specified * in a constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The default concurrency level for this table, used when not otherwise * specified in a constructor. */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * The maximum number of segments to allow; used to bound constructor * arguments. */ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative /** * Number of unsynchronized retries in size and containsValue methods before * resorting to locking. This is used to avoid unbounded retries if tables * undergo continuous modification which would make it impossible to obtain * an accurate result. */ static final int RETRIES_BEFORE_LOCK = 2; /* ---------------- Fields -------------- */ /** * Mask value for indexing into segments. The upper bits of a key's hash * code are used to choose the segment. */ final int segmentMask; /** * Shift value for indexing within segments. */ final int segmentShift; /** * The segments, each of which is a specialized hash table */ final Segment[] segments; Set keySet; Set> entrySet; Collection values; /* ---------------- Small Utilities -------------- */ /** * Applies a supplemental hash function to a given hashCode, which defends * against poor quality hash functions. This is critical because * ConcurrentReferenceHashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ in lower * or upper bits. */ private static int hash(int h) { // Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += h << 15 ^ 0xffffcd7d; h ^= h >>> 10; h += h << 3; h ^= h >>> 6; h += (h << 2) + (h << 14); return h ^ h >>> 16; } /** * Returns the segment that should be used for key with given hash. * * @param hash the hash code for the key * @return the segment */ Segment segmentFor(int hash) { return segments[hash >>> segmentShift & segmentMask]; } private static int hashOf(Object key) { return hash(key.hashCode()); } /* ---------------- Inner Classes -------------- */ /** * A weak-key reference which stores the key hash needed for reclamation. */ static final class WeakKeyReference extends WeakReference { final int hash; WeakKeyReference(K key, int hash, ReferenceQueue refQueue) { super(key, refQueue); this.hash = hash; } public int keyHash() { return hash; } public Object keyRef() { return this; } } /** * ConcurrentReferenceHashMap list entry. Note that this is never exported * out as a user-visible Map.Entry. * * Because the value field is volatile, not final, it is legal wrt * the Java Memory Model for an unsynchronized reader to see null * instead of initial value when read via a data race. Although a * reordering leading to this is not likely to ever actually * occur, the Segment.readValueUnderLock method is used as a * backup in case a null (pre-initialized) value is ever seen in * an unsynchronized access method. */ static final class HashEntry { final Object keyRef; final int hash; volatile Object valueRef; final HashEntry next; HashEntry( K key, int hash, HashEntry next, V value, ReferenceQueue refQueue) { this.hash = hash; this.next = next; keyRef = new WeakKeyReference(key, hash, refQueue); valueRef = value; } @SuppressWarnings("unchecked") K key() { return ((Reference) keyRef).get(); } V value() { return dereferenceValue(valueRef); } @SuppressWarnings("unchecked") V dereferenceValue(Object value) { if (value instanceof WeakKeyReference) { return ((Reference) value).get(); } return (V) value; } void setValue(V value) { valueRef = value; } @SuppressWarnings("unchecked") static HashEntry[] newArray(int i) { return new HashEntry[i]; } } /** * Segments are specialized versions of hash tables. This subclasses from * ReentrantLock opportunistically, just to simplify some locking and avoid * separate construction. */ static final class Segment extends ReentrantLock { /* * Segments maintain a table of entry lists that are ALWAYS kept in a * consistent state, so can be read without locking. Next fields of * nodes are immutable (final). All list additions are performed at the * front of each bin. This makes it easy to check changes, and also fast * to traverse. When nodes would otherwise be changed, new nodes are * created to replace them. This works well for hash tables since the * bin lists tend to be short. (The average length is less than two for * the default load factor threshold.) * * Read operations can thus proceed without locking, but rely on * selected uses of volatiles to ensure that completed write operations * performed by other threads are noticed. For most purposes, the * "count" field, tracking the number of elements, serves as that * volatile variable ensuring visibility. This is convenient because * this field needs to be read in many read operations anyway: * * - All (unsynchronized) read operations must first read the * "count" field, and should not look at table entries if * it is 0. * * - All (synchronized) write operations should write to * the "count" field after structurally changing any bin. * The operations must not take any action that could even * momentarily cause a concurrent read operation to see * inconsistent data. This is made easier by the nature of * the read operations in Map. For example, no operation * can reveal that the table has grown but the threshold * has not yet been updated, so there are no atomicity * requirements for this with respect to reads. * * As a guide, all critical volatile reads and writes to the count field * are marked in code comments. */ private static final long serialVersionUID = -8328104880676891126L; /** * The number of elements in this segment's region. */ transient volatile int count; /** * Number of updates that alter the size of the table. This is used * during bulk-read methods to make sure they see a consistent snapshot: * If modCounts change during a traversal of segments computing size or * checking containsValue, then we might have an inconsistent view of * state so (usually) must retry. */ int modCount; /** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always (capacity * loadFactor).) */ int threshold; /** * The per-segment table. */ transient volatile HashEntry[] table; /** * The load factor for the hash table. Even though this value is same * for all segments, it is replicated to avoid needing links to outer * object. */ final float loadFactor; /** * The collected weak-key reference queue for this segment. This should * be (re)initialized whenever table is assigned, */ transient volatile ReferenceQueue refQueue; Segment(int initialCapacity, float lf) { loadFactor = lf; setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") static Segment[] newArray(int i) { return new Segment[i]; } private static boolean keyEq(Object src, Object dest) { return src.equals(dest); } /** * Sets table to new HashEntry array. Call only while holding lock or in * constructor. */ void setTable(HashEntry[] newTable) { threshold = (int) (newTable.length * loadFactor); table = newTable; refQueue = new ReferenceQueue(); } /** * Returns properly casted first entry of bin for given hash. */ HashEntry getFirst(int hash) { HashEntry[] tab = table; return tab[hash & tab.length - 1]; } HashEntry newHashEntry( K key, int hash, HashEntry next, V value) { return new HashEntry( key, hash, next, value, refQueue); } /** * Reads value field of an entry under lock. Called if value field ever * appears to be null. This is possible only if a compiler happens to * reorder a HashEntry initialization with its table assignment, which * is legal under memory model but is not known to ever occur. */ V readValueUnderLock(HashEntry e) { lock(); try { removeStale(); return e.value(); } finally { unlock(); } } /* Specialized implementations of map methods */ V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { Object opaque = e.valueRef; if (opaque != null) { return e.dereferenceValue(opaque); } return readValueUnderLock(e); // recheck } e = e.next; } } return null; } boolean containsKey(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { return true; } e = e.next; } } return false; } boolean containsValue(Object value) { if (count != 0) { // read-volatile for (HashEntry e: table) { for (; e != null; e = e.next) { Object opaque = e.valueRef; V v; if (opaque == null) { v = readValueUnderLock(e); // recheck } else { v = e.dereferenceValue(opaque); } if (value.equals(v)) { return true; } } } } return false; } boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { removeStale(); HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } boolean replaced = false; if (e != null && oldValue.equals(e.value())) { replaced = true; e.setValue(newValue); } return replaced; } finally { unlock(); } } V replace(K key, int hash, V newValue) { lock(); try { removeStale(); HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { oldValue = e.value(); e.setValue(newValue); } return oldValue; } finally { unlock(); } } V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { removeStale(); int c = count; if (c ++ > threshold) { // ensure capacity int reduced = rehash(); if (reduced > 0) { count = (c -= reduced) - 1; // write-volatile } } HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue; if (e != null) { oldValue = e.value(); if (!onlyIfAbsent) { e.setValue(value); } } else { oldValue = null; ++ modCount; tab[index] = newHashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } } int rehash() { HashEntry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) { return 0; } /* * Reclassify nodes in each list to new Map. Because we are using * power-of-two expansion, the elements from each bin must either * stay at same index, or move with a power of two offset. We * eliminate unnecessary node creation by catching cases where old * nodes can be reused because their next fields won't change. * Statistically, at the default threshold, only about one-sixth of * them need cloning when a table doubles. The nodes they replace * will be garbage collectable as soon as they are no longer * referenced by any reader thread that may be in the midst of * traversing table right now. */ HashEntry[] newTable = HashEntry.newArray(oldCapacity << 1); threshold = (int) (newTable.length * loadFactor); int sizeMask = newTable.length - 1; int reduce = 0; for (HashEntry e: oldTable) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. if (e != null) { HashEntry next = e.next; int idx = e.hash & sizeMask; // Single node on list if (next == null) { newTable[idx] = e; } else { // Reuse trailing consecutive sequence at same slot HashEntry lastRun = e; int lastIdx = idx; for (HashEntry last = next; last != null; last = last.next) { int k = last.hash & sizeMask; if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; // Clone all remaining nodes for (HashEntry p = e; p != lastRun; p = p.next) { // Skip GC'd weak references K key = p.key(); if (key == null) { reduce++; continue; } int k = p.hash & sizeMask; HashEntry n = newTable[k]; newTable[k] = newHashEntry(key, p.hash, n, p.value()); } } } } table = newTable; return reduce; } /** * Remove; match on key only if value null, else match both. */ V remove(Object key, int hash, Object value, boolean refRemove) { lock(); try { if (!refRemove) { removeStale(); } int c = count - 1; HashEntry[] tab = table; int index = hash & tab.length - 1; HashEntry first = tab[index]; HashEntry e = first; // a reference remove operation compares the Reference instance while (e != null && key != e.keyRef && (refRemove || hash != e.hash || !keyEq(key, e.key()))) { e = e.next; } V oldValue = null; if (e != null) { V v = e.value(); if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay in list, // but all preceding ones need to be cloned. ++ modCount; HashEntry newFirst = e.next; for (HashEntry p = first; p != e; p = p.next) { K pKey = p.key(); if (pKey == null) { // Skip GC'd keys c --; continue; } newFirst = newHashEntry( pKey, p.hash, newFirst, p.value()); } tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } } @SuppressWarnings("rawtypes") void removeStale() { WeakKeyReference ref; while ((ref = (WeakKeyReference) refQueue.poll()) != null) { remove(ref.keyRef(), ref.keyHash(), null, true); } } void clear() { if (count != 0) { lock(); try { HashEntry[] tab = table; for (int i = 0; i < tab.length; i ++) { tab[i] = null; } ++ modCount; // replace the reference queue to avoid unnecessary stale // cleanups refQueue = new ReferenceQueue(); count = 0; // write-volatile } finally { unlock(); } } } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the specified initial capacity, load factor * and concurrency level. * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @param concurrencyLevel the estimated number of concurrently updating * threads. The implementation performs internal * sizing to try to accommodate this many threads. * @throws IllegalArgumentException if the initial capacity is negative or * the load factor or concurrencyLevel are * nonpositive. */ public ConcurrentWeakKeyHashMap( int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) { throw new IllegalArgumentException(); } if (concurrencyLevel > MAX_SEGMENTS) { concurrencyLevel = MAX_SEGMENTS; } // Find power-of-two sizes best matching arguments int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++ sshift; ssize <<= 1; } segmentShift = 32 - sshift; segmentMask = ssize - 1; segments = Segment.newArray(ssize); if (initialCapacity > MAXIMUM_CAPACITY) { initialCapacity = MAXIMUM_CAPACITY; } int c = initialCapacity / ssize; if (c * ssize < initialCapacity) { ++ c; } int cap = 1; while (cap < c) { cap <<= 1; } for (int i = 0; i < segments.length; ++ i) { segments[i] = new Segment(cap, loadFactor); } } /** * Creates a new, empty map with the specified initial capacity and load * factor and with the default reference types (weak keys, strong values), * and concurrencyLevel (16). * * @param initialCapacity The implementation performs internal sizing to * accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of * elements per bin exceeds this threshold. * @throws IllegalArgumentException if the initial capacity of elements is * negative or the load factor is * nonpositive */ public ConcurrentWeakKeyHashMap(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with the specified initial capacity, and with * default reference types (weak keys, strong values), load factor (0.75) * and concurrencyLevel (16). * * @param initialCapacity the initial capacity. The implementation performs * internal sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of elements is * negative. */ public ConcurrentWeakKeyHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new, empty map with a default initial capacity (16), reference * types (weak keys, strong values), default load factor (0.75) and * concurrencyLevel (16). */ public ConcurrentWeakKeyHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } /** * Creates a new map with the same mappings as the given map. The map is * created with a capacity of 1.5 times the number of mappings in the given * map or 16 (whichever is greater), and a default load factor (0.75) and * concurrencyLevel (16). * * @param m the map */ public ConcurrentWeakKeyHashMap(Map m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); putAll(m); } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings */ @Override public boolean isEmpty() { final Segment[] segments = this.segments; /* * We keep track of per-segment modCounts to avoid ABA problems in which * an element in one segment was added and in another removed during * traversal, in which case the table was never actually empty at any * point. Note the similar use of modCounts in the size() and * containsValue() methods, which are the only other methods also * susceptible to ABA problems. */ int[] mc = new int[segments.length]; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0) { return false; } else { mcsum += mc[i] = segments[i].modCount; } } // If mcsum happens to be zero, then we know we got a snapshot before // any modifications at all were made. This is probably common enough // to bother tracking. if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (segments[i].count != 0 || mc[i] != segments[i].modCount) { return false; } } } return true; } /** * Returns the number of key-value mappings in this map. If the map contains * more than Integer.MAX_VALUE elements, returns * Integer.MAX_VALUE. * * @return the number of key-value mappings in this map */ @Override public int size() { final Segment[] segments = this.segments; long sum = 0; long check = 0; int[] mc = new int[segments.length]; // Try a few times to get accurate count. On failure due to continuous // async changes in table, resort to locking. for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { check = 0; sum = 0; int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { sum += segments[i].count; mcsum += mc[i] = segments[i].modCount; } if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { check += segments[i].count; if (mc[i] != segments[i].modCount) { check = -1; // force retry break; } } } if (check == sum) { break; } } if (check != sum) { // Resort to locking all segments sum = 0; for (Segment segment: segments) { segment.lock(); } for (Segment segment: segments) { sum += segment.count; } for (Segment segment: segments) { segment.unlock(); } } if (sum > Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return (int) sum; } } /** * Returns the value to which the specified key is mapped, or {@code null} * if this map contains no mapping for the key. * *

More formally, if this map contains a mapping from a key {@code k} to * a value {@code v} such that {@code key.equals(k)}, then this method * returns {@code v}; otherwise it returns {@code null}. (There can be at * most one such mapping.) * * @throws NullPointerException if the specified key is null */ @Override public V get(Object key) { int hash = hashOf(key); return segmentFor(hash).get(key, hash); } /** * Tests if the specified object is a key in this table. * * @param key possible key * @return true if and only if the specified object is a key in * this table, as determined by the equals method; * false otherwise. * @throws NullPointerException if the specified key is null */ @Override public boolean containsKey(Object key) { int hash = hashOf(key); return segmentFor(hash).containsKey(key, hash); } /** * Returns true if this map maps one or more keys to the specified * value. Note: This method requires a full internal traversal of the hash * table, and so is much slower than method containsKey. * * @param value value whose presence in this map is to be tested * @return true if this map maps one or more keys to the specified * value * @throws NullPointerException if the specified value is null */ @Override public boolean containsValue(Object value) { if (value == null) { throw new NullPointerException(); } // See explanation of modCount use above final Segment[] segments = this.segments; int[] mc = new int[segments.length]; // Try a few times without locking for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) { int mcsum = 0; for (int i = 0; i < segments.length; ++ i) { mcsum += mc[i] = segments[i].modCount; if (segments[i].containsValue(value)) { return true; } } boolean cleanSweep = true; if (mcsum != 0) { for (int i = 0; i < segments.length; ++ i) { if (mc[i] != segments[i].modCount) { cleanSweep = false; break; } } } if (cleanSweep) { return false; } } // Resort to locking all segments for (Segment segment: segments) { segment.lock(); } boolean found = false; try { for (Segment segment: segments) { if (segment.containsValue(value)) { found = true; break; } } } finally { for (Segment segment: segments) { segment.unlock(); } } return found; } /** * Legacy method testing if some key maps into the specified value in this * table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure full compatibility * with class {@link Hashtable}, which supported this method prior to * introduction of the Java Collections framework. * * @param value a value to search for * @return true if and only if some key maps to the value * argument in this table as determined by the equals * method; false otherwise * @throws NullPointerException if the specified value is null */ public boolean contains(Object value) { return containsValue(value); } /** * Maps the specified key to the specified value in this table. Neither the * key nor the value can be null. * *

The value can be retrieved by calling the get method with a * key that is equal to the original key. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key or value is null */ @Override public V put(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, false); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V putIfAbsent(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).put(key, hash, value, true); } /** * Copies all of the mappings from the specified map to this one. These * mappings replace any mappings that this map had for any of the keys * currently in the specified map. * * @param m mappings to be stored in this map */ @Override public void putAll(Map m) { for (Map.Entry e: m.entrySet()) { put(e.getKey(), e.getValue()); } } /** * Removes the key (and its corresponding value) from this map. This method * does nothing if the key is not in the map. * * @param key the key that needs to be removed * @return the previous value associated with key, or null * if there was no mapping for key * @throws NullPointerException if the specified key is null */ @Override public V remove(Object key) { int hash = hashOf(key); return segmentFor(hash).remove(key, hash, null, false); } /** * @throws NullPointerException if the specified key is null */ public boolean remove(Object key, Object value) { int hash = hashOf(key); if (value == null) { return false; } return segmentFor(hash).remove(key, hash, value, false) != null; } /** * @throws NullPointerException if any of the arguments are null */ public boolean replace(K key, V oldValue, V newValue) { if (oldValue == null || newValue == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, oldValue, newValue); } /** * @return the previous value associated with the specified key, or * null if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V replace(K key, V value) { if (value == null) { throw new NullPointerException(); } int hash = hashOf(key); return segmentFor(hash).replace(key, hash, value); } /** * Removes all of the mappings from this map. */ @Override public void clear() { for (Segment segment: segments) { segment.clear(); } } /** * Removes any stale entries whose keys have been finalized. Use of this * method is normally not necessary since stale entries are automatically * removed lazily, when blocking operations are required. However, there are * some cases where this operation should be performed eagerly, such as * cleaning up old references to a ClassLoader in a multi-classloader * environment. * * Note: this method will acquire locks, one at a time, across all segments * of this table, so if it is to be used, it should be used sparingly. */ public void purgeStaleEntries() { for (Segment segment: segments) { segment.removeStale(); } } /** * Returns a {@link Set} view of the keys contained in this map. The set is * backed by the map, so changes to the map are reflected in the set, and * vice-versa. The set supports element removal, which removes the * corresponding mapping from this map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set keySet() { Set ks = keySet; return ks != null? ks : (keySet = new KeySet()); } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are reflected * in the collection, and vice-versa. The collection supports element * removal, which removes the corresponding mapping from this map, via the * Iterator.remove, Collection.remove, removeAll, * retainAll, and clear operations. It does not support * the add or addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Collection values() { Collection vs = values; return vs != null? vs : (values = new Values()); } /** * Returns a {@link Set} view of the mappings contained in this map. * The set is backed by the map, so changes to the map are reflected in the * set, and vice-versa. The set supports element removal, which removes the * corresponding mapping from the map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * *

The view's iterator is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. */ @Override public Set> entrySet() { Set> es = entrySet; return es != null? es : (entrySet = new EntrySet()); } /** * Returns an enumeration of the keys in this table. * * @return an enumeration of the keys in this table * @see #keySet() */ public Enumeration keys() { return new KeyIterator(); } /** * Returns an enumeration of the values in this table. * * @return an enumeration of the values in this table * @see #values() */ public Enumeration elements() { return new ValueIterator(); } /* ---------------- Iterator Support -------------- */ abstract class HashIterator { int nextSegmentIndex; int nextTableIndex; HashEntry[] currentTable; HashEntry nextEntry; HashEntry lastReturned; K currentKey; // Strong reference to weak key (prevents gc) HashIterator() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); } public void rewind() { nextSegmentIndex = segments.length - 1; nextTableIndex = -1; currentTable = null; nextEntry = null; lastReturned = null; currentKey = null; advance(); } public boolean hasMoreElements() { return hasNext(); } final void advance() { if (nextEntry != null && (nextEntry = nextEntry.next) != null) { return; } while (nextTableIndex >= 0) { if ((nextEntry = currentTable[nextTableIndex --]) != null) { return; } } while (nextSegmentIndex >= 0) { Segment seg = segments[nextSegmentIndex --]; if (seg.count != 0) { currentTable = seg.table; for (int j = currentTable.length - 1; j >= 0; -- j) { if ((nextEntry = currentTable[j]) != null) { nextTableIndex = j - 1; return; } } } } } public boolean hasNext() { while (nextEntry != null) { if (nextEntry.key() != null) { return true; } advance(); } return false; } HashEntry nextEntry() { do { if (nextEntry == null) { throw new NoSuchElementException(); } lastReturned = nextEntry; currentKey = lastReturned.key(); advance(); } while (currentKey == null); // Skip GC'd keys return lastReturned; } public void remove() { if (lastReturned == null) { throw new IllegalStateException(); } ConcurrentWeakKeyHashMap.this.remove(currentKey); lastReturned = null; } } final class KeyIterator extends HashIterator implements ReusableIterator, Enumeration { public K next() { return nextEntry().key(); } public K nextElement() { return nextEntry().key(); } } final class ValueIterator extends HashIterator implements ReusableIterator, Enumeration { public V next() { return nextEntry().value(); } public V nextElement() { return nextEntry().value(); } } /* * This class is needed for JDK5 compatibility. */ static class SimpleEntry implements Entry { private final K key; private V value; public SimpleEntry(K key, V value) { this.key = key; this.value = value; } public SimpleEntry(Entry entry) { key = entry.getKey(); value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } @SuppressWarnings("rawtypes") Map.Entry e = (Map.Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } @Override public int hashCode() { return (key == null? 0 : key.hashCode()) ^ (value == null? 0 : value.hashCode()); } @Override public String toString() { return key + "=" + value; } private static boolean eq(Object o1, Object o2) { return o1 == null? o2 == null : o1.equals(o2); } } /** * Custom Entry class used by EntryIterator.next(), that relays setValue * changes to the underlying map. */ final class WriteThroughEntry extends SimpleEntry { WriteThroughEntry(K k, V v) { super(k, v); } /** * Set our entry's value and write through to the map. The value to * return is somewhat arbitrary here. Since a WriteThroughEntry does not * necessarily track asynchronous changes, the most recent "previous" * value could be different from what we return (or could even have been * removed in which case the put will re-establish). We do not and can * not guarantee more. */ @Override public V setValue(V value) { if (value == null) { throw new NullPointerException(); } V v = super.setValue(value); put(getKey(), value); return v; } } final class EntryIterator extends HashIterator implements ReusableIterator> { public Map.Entry next() { HashEntry e = nextEntry(); return new WriteThroughEntry(e.key(), e.value()); } } final class KeySet extends AbstractSet { @Override public Iterator iterator() { return new KeyIterator(); } @Override public int size() { return ConcurrentWeakKeyHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentWeakKeyHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object o) { return ConcurrentWeakKeyHashMap.this.remove(o) != null; } @Override public void clear() { ConcurrentWeakKeyHashMap.this.clear(); } } final class Values extends AbstractCollection { @Override public Iterator iterator() { return new ValueIterator(); } @Override public int size() { return ConcurrentWeakKeyHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentWeakKeyHashMap.this.isEmpty(); } @Override public boolean contains(Object o) { return containsValue(o); } @Override public void clear() { ConcurrentWeakKeyHashMap.this.clear(); } } final class EntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new EntryIterator(); } @Override public boolean contains(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; V v = get(e.getKey()); return v != null && v.equals(e.getValue()); } @Override public boolean remove(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; return ConcurrentWeakKeyHashMap.this.remove(e.getKey(), e.getValue()); } @Override public int size() { return ConcurrentWeakKeyHashMap.this.size(); } @Override public boolean isEmpty() { return ConcurrentWeakKeyHashMap.this.isEmpty(); } @Override public void clear() { ConcurrentWeakKeyHashMap.this.clear(); } } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ConversionUtil.java000066400000000000000000000062021225554127700312160ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; /** * Conversion utility class to parse a property represented as a string or * an object. */ public final class ConversionUtil { /** * Converts the specified object into an integer. */ public static int toInt(Object value) { if (value instanceof Number) { return ((Number) value).intValue(); } else { return Integer.parseInt(String.valueOf(value)); } } /** * Converts the specified object into a boolean. */ public static boolean toBoolean(Object value) { if (value instanceof Boolean) { return ((Boolean) value).booleanValue(); } if (value instanceof Number) { return ((Number) value).intValue() != 0; } else { String s = String.valueOf(value); if (s.length() == 0) { return false; } try { return Integer.parseInt(s) != 0; } catch (NumberFormatException e) { // Proceed } switch (Character.toUpperCase(s.charAt(0))) { case 'T': case 'Y': return true; } return false; } } private static final Pattern ARRAY_DELIM = Pattern.compile("[, \\t\\n\\r\\f\\e\\a]"); /** * Converts the specified object into an array of strings. */ public static String[] toStringArray(Object value) { if (value instanceof String[]) { return (String[]) value; } if (value instanceof Iterable) { List answer = new ArrayList(); for (Object v: (Iterable) value) { if (v == null) { answer.add(null); } else { answer.add(String.valueOf(v)); } } return answer.toArray(new String[answer.size()]); } return ARRAY_DELIM.split(String.valueOf(value)); } private static final String[] INTEGERS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", }; public static String toString(int value) { if (value >= 0 && value < INTEGERS.length) { return INTEGERS[value]; } else { return Integer.toString(value); } } private ConversionUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/DeadLockProofWorker.java000066400000000000000000000031111225554127700320750ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.concurrent.Executor; /** */ public final class DeadLockProofWorker { /** * An internal use only thread-local variable that tells the * {@link Executor} that this worker acquired a worker thread from. */ public static final ThreadLocal PARENT = new ThreadLocal(); public static void start(final Executor parent, final Runnable runnable) { if (parent == null) { throw new NullPointerException("parent"); } if (runnable == null) { throw new NullPointerException("runnable"); } parent.execute(new Runnable() { public void run() { PARENT.set(parent); try { runnable.run(); } finally { PARENT.remove(); } } }); } private DeadLockProofWorker() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/DetectionUtil.java000066400000000000000000000100471225554127700310110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicInteger; /** * Utility that detects various properties specific to the current runtime * environment, such as Java version and the availability of the * {@code sun.misc.Unsafe} object. * *
* You can disable the use of {@code sun.misc.Unsafe} if you specify * the System property org.jboss.netty.tryUnsafe with * value of {@code false}. Default is {@code true}. */ public final class DetectionUtil { private static final int JAVA_VERSION = javaVersion0(); private static final boolean HAS_UNSAFE = hasUnsafe(AtomicInteger.class.getClassLoader()); private static final boolean IS_WINDOWS; static { String os = SystemPropertyUtil.get("os.name", "").toLowerCase(); // windows IS_WINDOWS = os.contains("win"); } /** * Return {@code true} if the JVM is running on Windows * */ public static boolean isWindows() { return IS_WINDOWS; } public static boolean hasUnsafe() { return HAS_UNSAFE; } public static int javaVersion() { return JAVA_VERSION; } private static boolean hasUnsafe(ClassLoader loader) { boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false); if (noUnsafe) { return false; } // Legacy properties boolean tryUnsafe; if (SystemPropertyUtil.contains("io.netty.tryUnsafe")) { tryUnsafe = SystemPropertyUtil.getBoolean("io.netty.tryUnsafe", true); } else { tryUnsafe = SystemPropertyUtil.getBoolean("org.jboss.netty.tryUnsafe", true); } if (!tryUnsafe) { return false; } try { Class unsafeClazz = Class.forName("sun.misc.Unsafe", true, loader); return hasUnsafeField(unsafeClazz); } catch (Exception e) { // Ignore } return false; } private static boolean hasUnsafeField(final Class unsafeClass) throws PrivilegedActionException { return AccessController.doPrivileged(new PrivilegedExceptionAction() { public Boolean run() throws Exception { unsafeClass.getDeclaredField("theUnsafe"); return true; } }); } private static int javaVersion0() { try { // Check if its android, if so handle it the same way as java6. // // See https://github.com/netty/netty/issues/282 Class.forName("android.app.Application"); return 6; } catch (ClassNotFoundException e) { //Ignore } try { Class.forName( "java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader()); return 7; } catch (Exception e) { // Ignore } try { Class.forName( "java.util.ArrayDeque", false, Queue.class.getClassLoader()); return 6; } catch (Exception e) { // Ignore } return 5; } private DetectionUtil() { // only static method supported } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ExecutorUtil.java000066400000000000000000000111771225554127700306760ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; /** * Shuts down a list of {@link Executor}s. {@link #terminate(Executor...)} will * shut down all specified {@link ExecutorService}s immediately and wait for * their termination. An {@link Executor} which is not an {@link ExecutorService} * will be ignored silently. */ public final class ExecutorUtil { /** * Try to call {@link ExecutorService#shutdownNow()} */ public static void shutdownNow(Executor executor) { if (executor instanceof ExecutorService) { ExecutorService es = (ExecutorService) executor; try { es.shutdownNow(); } catch (SecurityException ex) { // Running in a restricted environment - fall back. try { es.shutdown(); } catch (SecurityException ex2) { // Running in a more restricted environment. // Can't shut down this executor - skip to the next. } catch (NullPointerException ex2) { // Some JDK throws NPE here, but shouldn't. } } catch (NullPointerException ex) { // Some JDK throws NPE here, but shouldn't. } } } /** * Returns {@code true} if and only if the specified {@code executor} * is an {@link ExecutorService} and is shut down. Please note that this * method returns {@code false} if the specified {@code executor} is not an * {@link ExecutorService}. */ public static boolean isShutdown(Executor executor) { if (executor instanceof ExecutorService) { if (((ExecutorService) executor).isShutdown()) { return true; } } return false; } /** * Shuts down the specified executors. */ public static void terminate(Executor... executors) { terminate(DeadLockProofWorker.PARENT, executors); } /** * Shuts down the specified executors using the given {@link ThreadLocal} to check if there is a deadlock */ public static void terminate(ThreadLocal deadLockChecker, Executor... executors) { // Check nulls. if (executors == null) { throw new NullPointerException("executors"); } Executor[] executorsCopy = new Executor[executors.length]; for (int i = 0; i < executors.length; i ++) { if (executors[i] == null) { throw new NullPointerException("executors[" + i + ']'); } executorsCopy[i] = executors[i]; } // Check dead lock. final Executor currentParent = deadLockChecker.get(); if (currentParent != null) { for (Executor e: executorsCopy) { if (e == currentParent) { throw new IllegalStateException( "An Executor cannot be shut down from the thread " + "acquired from itself. Please make sure you are " + "not calling releaseExternalResources() from an " + "I/O worker thread."); } } } // Shut down all executors. boolean interrupted = false; for (Executor e: executorsCopy) { if (!(e instanceof ExecutorService)) { continue; } ExecutorService es = (ExecutorService) e; for (;;) { shutdownNow(es); try { if (es.awaitTermination(100, TimeUnit.MILLISECONDS)) { break; } } catch (InterruptedException ex) { interrupted = true; } } } if (interrupted) { Thread.currentThread().interrupt(); } } private ExecutorUtil() { } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/NonReentrantLock.java000066400000000000000000000043441225554127700314660ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; public final class NonReentrantLock extends AbstractQueuedSynchronizer implements Lock { private static final long serialVersionUID = -833780837233068610L; private Thread owner; public void lock() { acquire(1); } public void lockInterruptibly() throws InterruptedException { acquireInterruptibly(1); } public boolean tryLock() { return tryAcquire(1); } public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return tryAcquireNanos(1, unit.toNanos(time)); } public void unlock() { release(1); } public boolean isHeldByCurrentThread() { return isHeldExclusively(); } public Condition newCondition() { return new ConditionObject(); } @Override protected boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { owner = Thread.currentThread(); return true; } return false; } @Override protected boolean tryRelease(int releases) { if (Thread.currentThread() != owner) { throw new IllegalMonitorStateException(); } owner = null; setState(0); return true; } @Override protected boolean isHeldExclusively() { return getState() != 0 && owner == Thread.currentThread(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ReusableIterator.java000066400000000000000000000014171225554127700315120ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.Iterator; public interface ReusableIterator extends Iterator { void rewind(); } SharedResourceMisuseDetector.java000066400000000000000000000042551225554127700337600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** * Warn when user creates too many instances to avoid {@link OutOfMemoryError}. */ public class SharedResourceMisuseDetector { private static final int MAX_ACTIVE_INSTANCES = 256; private static final InternalLogger logger = InternalLoggerFactory.getInstance(SharedResourceMisuseDetector.class); private final Class type; private final AtomicLong activeInstances = new AtomicLong(); private final AtomicBoolean logged = new AtomicBoolean(); public SharedResourceMisuseDetector(Class type) { if (type == null) { throw new NullPointerException("type"); } this.type = type; } public void increase() { if (activeInstances.incrementAndGet() > MAX_ACTIVE_INSTANCES) { if (logger.isWarnEnabled()) { if (logged.compareAndSet(false, true)) { logger.warn( "You are creating too many " + type.getSimpleName() + " instances. " + type.getSimpleName() + " is a shared resource that must be reused across the" + " application, so that only a few instances are created."); } } } } public void decrease() { activeInstances.decrementAndGet(); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/StackTraceSimplifier.java000066400000000000000000000056501225554127700323110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.util.DebugUtil; import org.jboss.netty.util.ThreadRenamingRunnable; /** * Simplifies an exception stack trace by removing unnecessary * {@link StackTraceElement}s. Please note that the stack trace simplification * is disabled if {@linkplain DebugUtil debug mode} is turned on. */ public final class StackTraceSimplifier { private static final boolean SIMPLIFY_STACK_TRACE = !DebugUtil.isDebugEnabled(); private static final Pattern EXCLUDED_STACK_TRACE = Pattern.compile( "^org\\.jboss\\.netty\\." + "(util\\.(ThreadRenamingRunnable|internal\\.DeadLockProofWorker)" + "|channel\\.(SimpleChannel(Upstream|Downstream)?Handler|(Default|Static)ChannelPipeline.*))(\\$.*)?$"); /** * Removes unnecessary {@link StackTraceElement}s from the specified * exception. {@link ThreadRenamingRunnable}, {@link SimpleChannelHandler}, * and {@link ChannelPipeline} implementations will be dropped from the * trace. */ public static void simplify(Throwable e) { if (!SIMPLIFY_STACK_TRACE) { return; } if (e.getCause() != null) { simplify(e.getCause()); } StackTraceElement[] trace = e.getStackTrace(); if (trace == null || trace.length == 0) { return; } // Perhaps Netty bug. Let us not strip things out. if (EXCLUDED_STACK_TRACE.matcher(trace[0].getClassName()).matches()) { return; } List simpleTrace = new ArrayList(trace.length); simpleTrace.add(trace[0]); // Remove unnecessary stack trace elements. for (int i = 1; i < trace.length; i ++) { if (EXCLUDED_STACK_TRACE.matcher(trace[i].getClassName()).matches()) { continue; } simpleTrace.add(trace[i]); } e.setStackTrace( simpleTrace.toArray(new StackTraceElement[simpleTrace.size()])); } private StackTraceSimplifier() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/StringUtil.java000066400000000000000000000116261225554127700303450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.ArrayList; import java.util.Formatter; import java.util.List; /** * String utility class. */ public final class StringUtil { private StringUtil() { // Unused. } public static final String NEWLINE; static { String newLine; try { newLine = new Formatter().format("%n").toString(); } catch (Exception e) { newLine = "\n"; } NEWLINE = newLine; } /** * Strip an Object of it's ISO control characters. * * @param value * The Object that should be stripped. This objects toString method will * called and the result passed to {@link #stripControlCharacters(String)}. * @return {@code String} * A new String instance with its hexadecimal control characters replaced * by a space. Or the unmodified String if it does not contain any ISO * control characters. */ public static String stripControlCharacters(Object value) { if (value == null) { return null; } return stripControlCharacters(value.toString()); } /** * Strip a String of it's ISO control characters. * * @param value * The String that should be stripped. * @return {@code String} * A new String instance with its hexadecimal control characters replaced * by a space. Or the unmodified String if it does not contain any ISO * control characters. */ public static String stripControlCharacters(String value) { if (value == null) { return null; } boolean hasControlChars = false; for (int i = value.length() - 1; i >= 0; i --) { if (Character.isISOControl(value.charAt(i))) { hasControlChars = true; break; } } if (!hasControlChars) { return value; } StringBuilder buf = new StringBuilder(value.length()); int i = 0; // Skip initial control characters (i.e. left trim) for (; i < value.length(); i ++) { if (!Character.isISOControl(value.charAt(i))) { break; } } // Copy non control characters and substitute control characters with // a space. The last control characters are trimmed. boolean suppressingControlChars = false; for (; i < value.length(); i ++) { if (Character.isISOControl(value.charAt(i))) { suppressingControlChars = true; continue; } else { if (suppressingControlChars) { suppressingControlChars = false; buf.append(' '); } buf.append(value.charAt(i)); } } return buf.toString(); } private static final String EMPTY_STRING = ""; /** * Splits the specified {@link String} with the specified delimiter. This operation is a simplified and optimized * version of {@link String#split(String)}. */ public static String[] split(String value, char delim) { final int end = value.length(); final List res = new ArrayList(); int start = 0; for (int i = 0; i < end; i ++) { if (value.charAt(i) == delim) { if (start == i) { res.add(EMPTY_STRING); } else { res.add(value.substring(start, i)); } start = i + 1; } } if (start == 0) { // If no delimiter was found in the value res.add(value); } else { if (start != end) { // Add the last element if it's not empty. res.add(value.substring(start, end)); } else { // Truncate trailing empty elements. for (int i = res.size() - 1; i >= 0; i --) { if (res.get(i).length() == 0) { res.remove(i); } else { break; } } } } return res.toArray(new String[res.size()]); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/SystemPropertyUtil.java000066400000000000000000000147711225554127700321340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; /** * A collection of utility methods to retrieve and parse the values of the Java system properties. */ public final class SystemPropertyUtil { @SuppressWarnings("all") private static boolean initializedLogger; private static final InternalLogger logger; private static boolean loggedException; static { logger = InternalLoggerFactory.getInstance(SystemPropertyUtil.class); initializedLogger = true; } /** * Returns {@code true} if and only if the system property with the specified {@code key} * exists. */ public static boolean contains(String key) { return get(key) != null; } /** * Returns the value of the Java system property with the specified * {@code key}, while falling back to {@code null} if the property access fails. * * @return the property value or {@code null} */ public static String get(String key) { return get(key, null); } /** * Returns the value of the Java system property with the specified * {@code key}, while falling back to the specified default value if * the property access fails. * * @return the property value. * {@code def} if there's no such property or if an access to the * specified property is not allowed. */ public static String get(String key, String def) { if (key == null) { throw new NullPointerException("key"); } if (key.length() == 0) { throw new IllegalArgumentException("key must not be empty."); } String value = null; try { value = System.getProperty(key); } catch (Exception e) { if (!loggedException) { log("Unable to retrieve a system property '" + key + "'; default values will be used.", e); loggedException = true; } } if (value == null) { return def; } return value; } /** * Returns the value of the Java system property with the specified * {@code key}, while falling back to the specified default value if * the property access fails. * * @return the property value. * {@code def} if there's no such property or if an access to the * specified property is not allowed. */ public static boolean getBoolean(String key, boolean def) { String value = get(key); if (value == null) { return def; } value = value.trim().toLowerCase(); if (value.length() == 0) { return true; } if ("true".equals(value) || "yes".equals(value) || "1".equals(value)) { return true; } if ("false".equals(value) || "no".equals(value) || "0".equals(value)) { return false; } log( "Unable to parse the boolean system property '" + key + "':" + value + " - " + "using the default value: " + def); return def; } private static final Pattern INTEGER_PATTERN = Pattern.compile("-?[0-9]+"); /** * Returns the value of the Java system property with the specified * {@code key}, while falling back to the specified default value if * the property access fails. * * @return the property value. * {@code def} if there's no such property or if an access to the * specified property is not allowed. */ public static int getInt(String key, int def) { String value = get(key); if (value == null) { return def; } value = value.trim().toLowerCase(); if (INTEGER_PATTERN.matcher(value).matches()) { try { return Integer.parseInt(value); } catch (Exception e) { // Ignore } } log( "Unable to parse the integer system property '" + key + "':" + value + " - " + "using the default value: " + def); return def; } /** * Returns the value of the Java system property with the specified * {@code key}, while falling back to the specified default value if * the property access fails. * * @return the property value. * {@code def} if there's no such property or if an access to the * specified property is not allowed. */ public static long getLong(String key, long def) { String value = get(key); if (value == null) { return def; } value = value.trim().toLowerCase(); if (INTEGER_PATTERN.matcher(value).matches()) { try { return Long.parseLong(value); } catch (Exception e) { // Ignore } } log( "Unable to parse the long integer system property '" + key + "':" + value + " - " + "using the default value: " + def); return def; } private static void log(String msg) { if (initializedLogger) { logger.warn(msg); } else { // Use JDK logging if logger was not initialized yet. Logger.getLogger(SystemPropertyUtil.class.getName()).log(Level.WARNING, msg); } } private static void log(String msg, Exception e) { if (initializedLogger) { logger.warn(msg, e); } else { // Use JDK logging if logger was not initialized yet. Logger.getLogger(SystemPropertyUtil.class.getName()).log(Level.WARNING, msg, e); } } private SystemPropertyUtil() { // Unused } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ThreadLocalBoolean.java000066400000000000000000000020511225554127700317130ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; public class ThreadLocalBoolean extends ThreadLocal { private final boolean defaultValue; public ThreadLocalBoolean() { this(false); } public ThreadLocalBoolean(boolean defaultValue) { this.defaultValue = defaultValue; } @Override protected Boolean initialValue() { return defaultValue? Boolean.TRUE : Boolean.FALSE; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/ThreadLocalRandom.java000066400000000000000000000100471225554127700315600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.netty.util.internal; import java.util.Random; /** * A random number generator isolated to the current thread. Like the * global {@link Random} generator used by the {@link * Math} class, a {@code ThreadLocalRandom} is initialized * with an internally generated seed that may not otherwise be * modified. When applicable, use of {@code ThreadLocalRandom} rather * than shared {@code Random} objects in concurrent programs will * typically encounter much less overhead and contention. Use of * {@code ThreadLocalRandom} is particularly appropriate when multiple * tasks use random numbers in parallel in thread pools. * *

Usages of this class should typically be of the form: * {@code ThreadLocalRandom.current().nextX(...)} (where * {@code X} is {@code Int}, {@code Long}, etc). * When all usages are of this form, it is never possible to * accidently share a {@code ThreadLocalRandom} across multiple threads. * *

This class also provides additional commonly used bounded random * generation methods. * * @since 1.7 */ final class ThreadLocalRandom extends Random { // same constants as Random, but must be redeclared because private private static final long multiplier = 0x5DEECE66DL; private static final long addend = 0xBL; private static final long mask = (1L << 48) - 1; /** * The random seed. We can't use super.seed. */ private long rnd; /** * Initialization flag to permit the first and only allowed call * to setSeed (inside Random constructor) to succeed. We can't * allow others since it would cause setting seed in one part of a * program to unintentionally impact other usages by the thread. */ private boolean initialized; // Padding to help avoid memory contention among seed updates in // different TLRs in the common case that they are located near // each other. @SuppressWarnings("unused") private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; /** * The actual ThreadLocal */ private static final ThreadLocal localRandom = new ThreadLocal() { @Override protected ThreadLocalRandom initialValue() { return new ThreadLocalRandom(); } }; /** * Returns the current thread's {@code ThreadLocalRandom}. * * @return the current thread's {@code ThreadLocalRandom} */ static ThreadLocalRandom current() { return localRandom.get(); } /** * Throws {@code UnsupportedOperationException}. Setting seeds in * this generator is not supported. * * @throws UnsupportedOperationException always */ @Override public void setSeed(long seed) { // We rely on the fact that the superclass no-arg constructor // invokes setSeed exactly once to initialize. if (initialized) { throw new UnsupportedOperationException(); } initialized = true; rnd = (seed ^ multiplier) & mask; } @Override protected int next(int bits) { rnd = rnd * multiplier + addend & mask; return (int) (rnd >>> 48 - bits); } private static final long serialVersionUID = -5851777807851030925L; } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/UnterminatableExecutor.java000066400000000000000000000022321225554127700327230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import java.util.concurrent.Executor; /** * Disables shutdown of an {@link Executor} by wrapping the {@link Executor}. */ public class UnterminatableExecutor implements Executor { private final Executor executor; public UnterminatableExecutor(Executor executor) { if (executor == null) { throw new NullPointerException("executor"); } this.executor = executor; } public void execute(Runnable command) { executor.execute(command); } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/000077500000000000000000000000001225554127700265025ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/Adler32.java000066400000000000000000000104401225554127700305400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class Adler32 { // largest prime smaller than 65536 private static final int BASE = 65521; // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 private static final int NMAX = 5552; static long adler32(long adler, byte[] buf, int index, int len) { if (buf == null) { return 1L; } long s1 = adler & 0xffff; long s2 = adler >> 16 & 0xffff; int k; while (len > 0) { k = len < NMAX? len : NMAX; len -= k; while (k >= 16) { s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; s1 += buf[index ++] & 0xff; s2 += s1; k -= 16; } if (k != 0) { do { s1 += buf[index ++] & 0xff; s2 += s1; } while (-- k != 0); } s1 %= BASE; s2 %= BASE; } return s2 << 16 | s1; } private Adler32() { // Utility class } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/CRC32.java000066400000000000000000000137301225554127700301250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class CRC32 { private static final int[] TABLE = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; static int crc32(int crc32, byte[] buf, int index, int len) { final int endIndex = index + len; crc32 ^= 0xffffffff; for (int i = index; i < endIndex; i ++) { crc32 = crc32 >>> 8 ^ TABLE[(crc32 ^ buf[i]) & 0xff]; } crc32 ^= 0xffffffff; return crc32; } private CRC32() { // Utility class } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/Deflate.java000066400000000000000000002012621225554127700307140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; import org.jboss.netty.util.internal.jzlib.JZlib.WrapperType; final class Deflate { private static final class Config { final int good_length; // reduce lazy search above this match length final int max_lazy; // do not perform lazy search above this match length final int nice_length; // quit search above this match length final int max_chain; final int func; Config(int good_length, int max_lazy, int nice_length, int max_chain, int func) { this.good_length = good_length; this.max_lazy = max_lazy; this.nice_length = nice_length; this.max_chain = max_chain; this.func = func; } } private static final int STORED = 0; private static final int FAST = 1; private static final int SLOW = 2; private static final Config[] config_table; static { config_table = new Config[10]; config_table[0] = new Config(0, 0, 0, 0, STORED); config_table[1] = new Config(4, 4, 8, 4, FAST); config_table[2] = new Config(4, 5, 16, 8, FAST); config_table[3] = new Config(4, 6, 32, 32, FAST); config_table[4] = new Config(4, 4, 16, 16, SLOW); config_table[5] = new Config(8, 16, 32, 32, SLOW); config_table[6] = new Config(8, 16, 128, 128, SLOW); config_table[7] = new Config(8, 32, 128, 256, SLOW); config_table[8] = new Config(32, 128, 258, 1024, SLOW); config_table[9] = new Config(32, 258, 258, 4096, SLOW); } private static final String[] z_errmsg = { "need dictionary", // Z_NEED_DICT 2 "stream end", // Z_STREAM_END 1 "", // Z_OK 0 "file error", // Z_ERRNO (-1) "stream error", // Z_STREAM_ERROR (-2) "data error", // Z_DATA_ERROR (-3) "insufficient memory", // Z_MEM_ERROR (-4) "buffer error", // Z_BUF_ERROR (-5) "incompatible version", // Z_VERSION_ERROR (-6) "" }; // block not completed, need more input or more output private static final int NeedMore = 0; // block flush performed private static final int BlockDone = 1; // finish started, need only more output at next deflate private static final int FinishStarted = 2; // finish done, accept no more input or output private static final int FinishDone = 3; private static final int INIT_STATE = 42; private static final int BUSY_STATE = 113; private static final int FINISH_STATE = 666; private static final int STORED_BLOCK = 0; private static final int STATIC_TREES = 1; private static final int DYN_TREES = 2; // The three kinds of block type private static final int Z_BINARY = 0; private static final int Z_ASCII = 1; private static final int Z_UNKNOWN = 2; private static final int Buf_size = 8 * 2; // repeat previous bit length 3-6 times (2 bits of repeat count) private static final int REP_3_6 = 16; // repeat a zero length 3-10 times (3 bits of repeat count) private static final int REPZ_3_10 = 17; // repeat a zero length 11-138 times (7 bits of repeat count) private static final int REPZ_11_138 = 18; private static final int MIN_MATCH = 3; private static final int MAX_MATCH = 258; private static final int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; private static final int END_BLOCK = 256; ZStream strm; // pointer back to this zlib stream int status; // as the name implies byte[] pending_buf; // output still pending int pending_buf_size; // size of pending_buf int pending_out; // next pending byte to output to the stream int pending; // nb of bytes in the pending buffer WrapperType wrapperType; private boolean wroteTrailer; byte data_type; // UNKNOWN, BINARY or ASCII int last_flush; // value of flush param for previous deflate call int w_size; // LZ77 window size (32K by default) int w_bits; // log2(w_size) (8..16) int w_mask; // w_size - 1 byte[] window; // Sliding window. Input bytes are read into the second half of the window, // and move to the first half later to keep a dictionary of at least wSize // bytes. With this organization, matches are limited to a distance of // wSize-MAX_MATCH bytes, but this ensures that IO is always // performed with a length multiple of the block size. Also, it limits // the window size to 64K, which is quite useful on MSDOS. // To do: use the user input buffer as sliding window. int window_size; // Actual size of window: 2*wSize, except when the user input buffer // is directly used as sliding window. short[] prev; // Link to older string with same hash index. To limit the size of this // array to 64K, this link is maintained only for the last 32K strings. // An index in this array is thus a window index modulo 32K. short[] head; // Heads of the hash chains or NIL. int ins_h; // hash index of string to be inserted int hash_size; // number of elements in hash table int hash_bits; // log2(hash_size) int hash_mask; // hash_size-1 // Number of bits by which ins_h must be shifted at each input // step. It must be such that after MIN_MATCH steps, the oldest // byte no longer takes part in the hash key, that is: // hash_shift * MIN_MATCH >= hash_bits int hash_shift; // Window position at the beginning of the current output block. Gets // negative when the window is moved backwards. int block_start; int match_length; // length of best match int prev_match; // previous match int match_available; // set if previous match exists int strstart; // start of string to insert int match_start; // start of matching string int lookahead; // number of valid bytes ahead in window // Length of the best match at previous step. Matches not greater than this // are discarded. This is used in the lazy match evaluation. int prev_length; // To speed up deflation, hash chains are never searched beyond this // length. A higher limit improves compression ratio but degrades the speed. int max_chain_length; // Attempt to find a better match only when the current match is strictly // smaller than this value. This mechanism is used only for compression // levels >= 4. int max_lazy_match; // Insert new strings in the hash table only if the match length is not // greater than this length. This saves time but degrades compression. // max_insert_length is used only for compression levels <= 3. int level; // compression level (1..9) int strategy; // favor or force Huffman coding // Use a faster search when the previous match is longer than this int good_match; // Stop searching when current match exceeds this int nice_match; final short[] dyn_ltree; // literal and length tree final short[] dyn_dtree; // distance tree final short[] bl_tree; // Huffman tree for bit lengths final Tree l_desc = new Tree(); // desc for literal tree final Tree d_desc = new Tree(); // desc for distance tree final Tree bl_desc = new Tree(); // desc for bit length tree // number of codes at each bit length for an optimal tree final short[] bl_count = new short[JZlib.MAX_BITS + 1]; // heap used to build the Huffman trees final int[] heap = new int[2 * JZlib.L_CODES + 1]; int heap_len; // number of elements in the heap int heap_max; // element of largest frequency // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. // The same heap array is used to build all trees. // Depth of each subtree used as tie breaker for trees of equal frequency final byte[] depth = new byte[2 * JZlib.L_CODES + 1]; int l_buf; // index for literals or lengths */ // Size of match buffer for literals/lengths. There are 4 reasons for // limiting lit_bufsize to 64K: // - frequencies can be kept in 16 bit counters // - if compression is not successful for the first block, all input // data is still in the window so we can still emit a stored block even // when input comes from standard input. (This can also be done for // all blocks if lit_bufsize is not greater than 32K.) // - if compression is not successful for a file smaller than 64K, we can // even emit a stored file instead of a stored block (saving 5 bytes). // This is applicable only for zip (not gzip or zlib). // - creating new Huffman trees less frequently may not provide fast // adaptation to changes in the input data statistics. (Take for // example a binary file with poorly compressible code followed by // a highly compressible string table.) Smaller buffer sizes give // fast adaptation but have of course the overhead of transmitting // trees more frequently. // - I can't count above 4 int lit_bufsize; int last_lit; // running index in l_buf // Buffer for distances. To simplify the code, d_buf and l_buf have // the same number of elements. To use different lengths, an extra flag // array would be necessary. int d_buf; // index of pendig_buf int opt_len; // bit length of current block with optimal trees int static_len; // bit length of current block with static trees int matches; // number of string matches in current block int last_eob_len; // bit length of EOB code for last block // Output buffer. bits are inserted starting at the bottom (least // significant bits). short bi_buf; // Number of valid bits in bi_buf. All bits above the last valid bit // are always zero. int bi_valid; private int gzipUncompressedBytes; Deflate() { dyn_ltree = new short[JZlib.HEAP_SIZE * 2]; dyn_dtree = new short[(2 * JZlib.D_CODES + 1) * 2]; // distance tree bl_tree = new short[(2 * JZlib.BL_CODES + 1) * 2]; // Huffman tree for bit lengths } private void lm_init() { window_size = 2 * w_size; // Set the default configuration parameters: max_lazy_match = config_table[level].max_lazy; good_match = config_table[level].good_length; nice_match = config_table[level].nice_length; max_chain_length = config_table[level].max_chain; strstart = 0; block_start = 0; lookahead = 0; match_length = prev_length = MIN_MATCH - 1; match_available = 0; ins_h = 0; } // Initialize the tree data structures for a new zlib stream. private void tr_init() { l_desc.dyn_tree = dyn_ltree; l_desc.stat_desc = StaticTree.static_l_desc; d_desc.dyn_tree = dyn_dtree; d_desc.stat_desc = StaticTree.static_d_desc; bl_desc.dyn_tree = bl_tree; bl_desc.stat_desc = StaticTree.static_bl_desc; bi_buf = 0; bi_valid = 0; last_eob_len = 8; // enough lookahead for inflate // Initialize the first block of the first file: init_block(); } private void init_block() { // Initialize the trees. for (int i = 0; i < JZlib.L_CODES; i ++) { dyn_ltree[i * 2] = 0; } for (int i = 0; i < JZlib.D_CODES; i ++) { dyn_dtree[i * 2] = 0; } for (int i = 0; i < JZlib.BL_CODES; i ++) { bl_tree[i * 2] = 0; } dyn_ltree[END_BLOCK * 2] = 1; opt_len = static_len = 0; last_lit = matches = 0; } // Restore the heap property by moving down the tree starting at node k, // exchanging a node with the smallest of its two sons if necessary, stopping // when the heap property is re-established (each father smaller than its // two sons). void pqdownheap(short[] tree, // the tree to restore int k // node to move down ) { int v = heap[k]; int j = k << 1; // left son of k while (j <= heap_len) { // Set j to the smallest of the two sons: if (j < heap_len && smaller(tree, heap[j + 1], heap[j], depth)) { j ++; } // Exit if v is smaller than both sons if (smaller(tree, v, heap[j], depth)) { break; } // Exchange v with the smallest son heap[k] = heap[j]; k = j; // And continue down the tree, setting j to the left son of k j <<= 1; } heap[k] = v; } private static boolean smaller(short[] tree, int n, int m, byte[] depth) { short tn2 = tree[n * 2]; short tm2 = tree[m * 2]; return tn2 < tm2 || tn2 == tm2 && depth[n] <= depth[m]; } // Scan a literal or distance tree to determine the frequencies of the codes // in the bit length tree. private void scan_tree(short[] tree, // the tree to be scanned int max_code // and its largest code of non zero frequency ) { int n; // iterates over all tree elements int prevlen = -1; // last emitted length int curlen; // length of current code int nextlen = tree[1]; // length of next code int count = 0; // repeat count of the current code int max_count = 7; // max repeat count int min_count = 4; // min repeat count if (nextlen == 0) { max_count = 138; min_count = 3; } tree[(max_code + 1) * 2 + 1] = (short) 0xffff; // guard for (n = 0; n <= max_code; n ++) { curlen = nextlen; nextlen = tree[(n + 1) * 2 + 1]; if (++ count < max_count && curlen == nextlen) { continue; } if (count < min_count) { bl_tree[curlen * 2] += count; } else if (curlen != 0) { if (curlen != prevlen) { bl_tree[curlen * 2] ++; } bl_tree[REP_3_6 * 2] ++; } else if (count <= 10) { bl_tree[REPZ_3_10 * 2] ++; } else { bl_tree[REPZ_11_138 * 2] ++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138; min_count = 3; } else if (curlen == nextlen) { max_count = 6; min_count = 3; } else { max_count = 7; min_count = 4; } } } // Construct the Huffman tree for the bit lengths and return the index in // bl_order of the last bit length code to send. private int build_bl_tree() { int max_blindex; // index of last bit length code of non zero freq // Determine the bit length frequencies for literal and distance trees scan_tree(dyn_ltree, l_desc.max_code); scan_tree(dyn_dtree, d_desc.max_code); // Build the bit length tree: bl_desc.build_tree(this); // opt_len now includes the length of the tree representations, except // the lengths of the bit lengths codes and the 5+5+4 bits for the counts. // Determine the number of bit length codes to send. The pkzip format // requires that at least 4 bit length codes be sent. (appnote.txt says // 3 but the actual value used is 4.) for (max_blindex = JZlib.BL_CODES - 1; max_blindex >= 3; max_blindex --) { if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] != 0) { break; } } // Update opt_len to include the bit length tree and counts opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; return max_blindex; } // Send the header for a block using dynamic Huffman trees: the counts, the // lengths of the bit length codes, the literal tree and the distance tree. // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. private void send_all_trees(int lcodes, int dcodes, int blcodes) { int rank; // index in bl_order send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt send_bits(dcodes - 1, 5); send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt for (rank = 0; rank < blcodes; rank ++) { send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3); } send_tree(dyn_ltree, lcodes - 1); // literal tree send_tree(dyn_dtree, dcodes - 1); // distance tree } // Send a literal or distance tree in compressed form, using the codes in // bl_tree. private void send_tree(short[] tree, // the tree to be sent int max_code // and its largest code of non zero frequency ) { int n; // iterates over all tree elements int prevlen = -1; // last emitted length int curlen; // length of current code int nextlen = tree[1]; // length of next code int count = 0; // repeat count of the current code int max_count = 7; // max repeat count int min_count = 4; // min repeat count if (nextlen == 0) { max_count = 138; min_count = 3; } for (n = 0; n <= max_code; n ++) { curlen = nextlen; nextlen = tree[(n + 1) * 2 + 1]; if (++ count < max_count && curlen == nextlen) { continue; } if (count < min_count) { do { send_code(curlen, bl_tree); } while (-- count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(curlen, bl_tree); count --; } send_code(REP_3_6, bl_tree); send_bits(count - 3, 2); } else if (count <= 10) { send_code(REPZ_3_10, bl_tree); send_bits(count - 3, 3); } else { send_code(REPZ_11_138, bl_tree); send_bits(count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138; min_count = 3; } else if (curlen == nextlen) { max_count = 6; min_count = 3; } else { max_count = 7; min_count = 4; } } } // Output a byte on the stream. // IN assertion: there is enough room in pending_buf. private void put_byte(byte[] p, int start, int len) { System.arraycopy(p, start, pending_buf, pending, len); pending += len; } private void put_byte(byte c) { pending_buf[pending ++] = c; } private void put_short(int w) { put_byte((byte) w/*&0xff*/); put_byte((byte) (w >>> 8)); } private void putShortMSB(int b) { put_byte((byte) (b >> 8)); put_byte((byte) b/*&0xff*/); } private void send_code(int c, short[] tree) { int c2 = c * 2; send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff); } private void send_bits(int value, int length) { int len = length; if (bi_valid > Buf_size - len) { int val = value; // bi_buf |= (val << bi_valid); bi_buf |= val << bi_valid & 0xffff; put_short(bi_buf); bi_buf = (short) (val >>> Buf_size - bi_valid); bi_valid += len - Buf_size; } else { // bi_buf |= (value) << bi_valid; bi_buf |= value << bi_valid & 0xffff; bi_valid += len; } } // Send one empty static block to give enough lookahead for inflate. // This takes 10 bits, of which 7 may remain in the bit buffer. // The current inflate code requires 9 bits of lookahead. If the // last two codes for the previous block (real code plus EOB) were coded // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode // the last real code. In this case we send two empty static blocks instead // of one. (There are no problems if the previous block is stored or fixed.) // To simplify the code, we assume the worst case of last real code encoded // on one bit only. private void _tr_align() { send_bits(STATIC_TREES << 1, 3); send_code(END_BLOCK, StaticTree.static_ltree); bi_flush(); // Of the 10 bits for the empty block, we have already sent // (10 - bi_valid) bits. The lookahead for the last real code (before // the EOB of the previous block) was thus at least one plus the length // of the EOB plus what we have just sent of the empty static block. if (1 + last_eob_len + 10 - bi_valid < 9) { send_bits(STATIC_TREES << 1, 3); send_code(END_BLOCK, StaticTree.static_ltree); bi_flush(); } last_eob_len = 7; } // Save the match info and tally the frequency counts. Return true if // the current block must be flushed. private boolean _tr_tally(int dist, // distance of matched string int lc // match length-MIN_MATCH or unmatched char (if dist==0) ) { pending_buf[d_buf + last_lit * 2] = (byte) (dist >>> 8); pending_buf[d_buf + last_lit * 2 + 1] = (byte) dist; pending_buf[l_buf + last_lit] = (byte) lc; last_lit ++; if (dist == 0) { // lc is the unmatched char dyn_ltree[lc * 2] ++; } else { matches ++; // Here, lc is the match length - MIN_MATCH dist --; // dist = match distance - 1 dyn_ltree[(Tree._length_code[lc] + JZlib.LITERALS + 1) * 2] ++; dyn_dtree[Tree.d_code(dist) * 2] ++; } if ((last_lit & 0x1fff) == 0 && level > 2) { // Compute an upper bound for the compressed length int out_length = last_lit * 8; int in_length = strstart - block_start; int dcode; for (dcode = 0; dcode < JZlib.D_CODES; dcode ++) { out_length += dyn_dtree[dcode * 2] * (5L + Tree.extra_dbits[dcode]); } out_length >>>= 3; if (matches < last_lit / 2 && out_length < in_length / 2) { return true; } } return last_lit == lit_bufsize - 1; // We avoid equality with lit_bufsize because of wraparound at 64K // on 16 bit machines and because stored blocks are restricted to // 64K-1 bytes. } // Send the block data compressed using the given Huffman trees private void compress_block(short[] ltree, short[] dtree) { int dist; // distance of matched string int lc; // match length or unmatched char (if dist == 0) int lx = 0; // running index in l_buf int code; // the code to send int extra; // number of extra bits to send if (last_lit != 0) { do { dist = pending_buf[d_buf + lx * 2] << 8 & 0xff00 | pending_buf[d_buf + lx * 2 + 1] & 0xff; lc = pending_buf[l_buf + lx] & 0xff; lx ++; if (dist == 0) { send_code(lc, ltree); // send a literal byte } else { // Here, lc is the match length - MIN_MATCH code = Tree._length_code[lc]; send_code(code + JZlib.LITERALS + 1, ltree); // send the length code extra = Tree.extra_lbits[code]; if (extra != 0) { lc -= Tree.base_length[code]; send_bits(lc, extra); // send the extra length bits } dist --; // dist is now the match distance - 1 code = Tree.d_code(dist); send_code(code, dtree); // send the distance code extra = Tree.extra_dbits[code]; if (extra != 0) { dist -= Tree.base_dist[code]; send_bits(dist, extra); // send the extra distance bits } } // literal or match pair ? // Check that the overlay between pending_buf and d_buf+l_buf is ok: } while (lx < last_lit); } send_code(END_BLOCK, ltree); last_eob_len = ltree[END_BLOCK * 2 + 1]; } // Set the data type to ASCII or BINARY, using a crude approximation: // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. // IN assertion: the fields freq of dyn_ltree are set and the total of all // frequencies does not exceed 64K (to fit in an int on 16 bit machines). private void set_data_type() { int n = 0; int ascii_freq = 0; int bin_freq = 0; while (n < 7) { bin_freq += dyn_ltree[n * 2]; n ++; } while (n < 128) { ascii_freq += dyn_ltree[n * 2]; n ++; } while (n < JZlib.LITERALS) { bin_freq += dyn_ltree[n * 2]; n ++; } data_type = (byte) (bin_freq > ascii_freq >>> 2? Z_BINARY : Z_ASCII); } // Flush the bit buffer, keeping at most 7 bits in it. private void bi_flush() { if (bi_valid == 16) { put_short(bi_buf); bi_buf = 0; bi_valid = 0; } else if (bi_valid >= 8) { put_byte((byte) bi_buf); bi_buf >>>= 8; bi_valid -= 8; } } // Flush the bit buffer and align the output on a byte boundary private void bi_windup() { if (bi_valid > 8) { put_short(bi_buf); } else if (bi_valid > 0) { put_byte((byte) bi_buf); } bi_buf = 0; bi_valid = 0; } // Copy a stored block, storing first the length and its // one's complement if requested. private void copy_block(int buf, // the input data int len, // its length boolean header // true if block header must be written ) { bi_windup(); // align on byte boundary last_eob_len = 8; // enough lookahead for inflate if (header) { put_short((short) len); put_short((short) ~len); } // while(len--!=0) { // put_byte(window[buf+index]); // index++; // } put_byte(window, buf, len); } private void flush_block_only(boolean eof) { _tr_flush_block(block_start >= 0? block_start : -1, strstart - block_start, eof); block_start = strstart; strm.flush_pending(); } // Copy without compression as much as possible from the input stream, return // the current block state. // This function does not insert new strings in the dictionary since // uncompressible data is probably not useful. This function is used // only for the level=0 compression option. // NOTE: this function should be optimized to avoid extra copying from // window to pending_buf. private int deflate_stored(int flush) { // Stored blocks are limited to 0xffff bytes, pending_buf is limited // to pending_buf_size, and each stored block has a 5 byte header: int max_block_size = 0xffff; int max_start; if (max_block_size > pending_buf_size - 5) { max_block_size = pending_buf_size - 5; } // Copy as much as possible from input to output: while (true) { // Fill the window as much as possible: if (lookahead <= 1) { fill_window(); if (lookahead == 0 && flush == JZlib.Z_NO_FLUSH) { return NeedMore; } if (lookahead == 0) { break; // flush the current block } } strstart += lookahead; lookahead = 0; // Emit a stored block if pending_buf will be full: max_start = block_start + max_block_size; if (strstart == 0 || strstart >= max_start) { // strstart == 0 is possible when wraparound on 16-bit machine lookahead = strstart - max_start; strstart = max_start; flush_block_only(false); if (strm.avail_out == 0) { return NeedMore; } } // Flush if we may have to slide, otherwise block_start may become // negative and the data will be gone: if (strstart - block_start >= w_size - MIN_LOOKAHEAD) { flush_block_only(false); if (strm.avail_out == 0) { return NeedMore; } } } flush_block_only(flush == JZlib.Z_FINISH); if (strm.avail_out == 0) { return flush == JZlib.Z_FINISH? FinishStarted : NeedMore; } return flush == JZlib.Z_FINISH? FinishDone : BlockDone; } // Send a stored block private void _tr_stored_block(int buf, // input block int stored_len, // length of input block boolean eof // true if this is the last block for a file ) { //noinspection PointlessArithmeticExpression send_bits((STORED_BLOCK << 1) + (eof? 1 : 0), 3); // send block type copy_block(buf, stored_len, true); // with header } // Determine the best encoding for the current block: dynamic trees, static // trees or store, and output the encoded block to the zip file. private void _tr_flush_block(int buf, // input block, or NULL if too old int stored_len, // length of input block boolean eof // true if this is the last block for a file ) { int opt_lenb, static_lenb; // opt_len and static_len in bytes int max_blindex = 0; // index of last bit length code of non zero freq // Build the Huffman trees unless a stored block is forced if (level > 0) { // Check if the file is ascii or binary if (data_type == Z_UNKNOWN) { set_data_type(); } // Construct the literal and distance trees l_desc.build_tree(this); d_desc.build_tree(this); // At this point, opt_len and static_len are the total bit lengths of // the compressed block data, excluding the tree representations. // Build the bit length tree for the above two trees, and get the index // in bl_order of the last bit length code to send. max_blindex = build_bl_tree(); // Determine the best encoding. Compute first the block length in bytes opt_lenb = opt_len + 3 + 7 >>> 3; static_lenb = static_len + 3 + 7 >>> 3; if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } } else { opt_lenb = static_lenb = stored_len + 5; // force a stored block } if (stored_len + 4 <= opt_lenb && buf != -1) { // 4: two words for the lengths // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. // Otherwise we can't have processed more than WSIZE input bytes since // the last block flush, because compression would have been // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to // transform a block into a stored block. _tr_stored_block(buf, stored_len, eof); } else if (static_lenb == opt_lenb) { send_bits((STATIC_TREES << 1) + (eof? 1 : 0), 3); compress_block(StaticTree.static_ltree, StaticTree.static_dtree); } else { send_bits((DYN_TREES << 1) + (eof? 1 : 0), 3); send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1); compress_block(dyn_ltree, dyn_dtree); } // The above check is made mod 2^32, for files larger than 512 MB // and uLong implemented on 32 bits. init_block(); if (eof) { bi_windup(); } } // Fill the window when the lookahead becomes insufficient. // Updates strstart and lookahead. // // IN assertion: lookahead < MIN_LOOKAHEAD // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD // At least one byte has been read, or avail_in == 0; reads are // performed for at least two bytes (required for the zip translate_eol // option -- not supported here). private void fill_window() { int n, m; int p; int more; // Amount of free space at the end of the window. do { more = window_size - lookahead - strstart; // Deal with !@#$% 64K limit: if (more == 0 && strstart == 0 && lookahead == 0) { more = w_size; } else if (more == -1) { // Very unlikely, but possible on 16 bit machine if strstart == 0 // and lookahead == 1 (input done one byte at time) more --; // If the window is almost full and there is insufficient lookahead, // move the upper half to the lower one to make room in the upper half. } else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) { System.arraycopy(window, w_size, window, 0, w_size); match_start -= w_size; strstart -= w_size; // we now have strstart >= MAX_DIST block_start -= w_size; // Slide the hash table (could be avoided with 32 bit values // at the expense of memory usage). We slide even when level == 0 // to keep the hash table consistent if we switch back to level > 0 // later. (Using level 0 permanently is not an optimal usage of // zlib, so we don't care about this pathological case.) n = hash_size; p = n; do { m = head[-- p] & 0xffff; head[p] = m >= w_size? (short) (m - w_size) : 0; } while (-- n != 0); n = w_size; p = n; do { m = prev[-- p] & 0xffff; prev[p] = m >= w_size? (short) (m - w_size) : 0; // If n is not on any hash chain, prev[n] is garbage but // its value will never be used. } while (-- n != 0); more += w_size; } if (strm.avail_in == 0) { return; } // If there was no sliding: // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && // more == window_size - lookahead - strstart // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) // => more >= window_size - 2*WSIZE + 2 // In the BIG_MEM or MMAP case (not yet supported), // window_size == input_size + MIN_LOOKAHEAD && // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. // Otherwise, window_size == 2*WSIZE so more >= 2. // If there was sliding, more >= WSIZE. So in all cases, more >= 2. n = strm.read_buf(window, strstart + lookahead, more); lookahead += n; // Initialize the hash value now that we have some input: if (lookahead >= MIN_MATCH) { ins_h = window[strstart] & 0xff; ins_h = (ins_h << hash_shift ^ window[strstart + 1] & 0xff) & hash_mask; } // If the whole input has less than MIN_MATCH bytes, ins_h is garbage, // but this is not important since only literal bytes will be emitted. } while (lookahead < MIN_LOOKAHEAD && strm.avail_in != 0); } // Compress as much as possible from the input stream, return the current // block state. // This function does not perform lazy evaluation of matches and inserts // new strings in the dictionary only for unmatched strings or for short // matches. It is used only for the fast compression options. private int deflate_fast(int flush) { // short hash_head = 0; // head of the hash chain int hash_head = 0; // head of the hash chain boolean bflush; // set if current block must be flushed while (true) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the next match, plus MIN_MATCH bytes to insert the // string following the next match. if (lookahead < MIN_LOOKAHEAD) { fill_window(); if (lookahead < MIN_LOOKAHEAD && flush == JZlib.Z_NO_FLUSH) { return NeedMore; } if (lookahead == 0) { break; // flush the current block } } // Insert the string window[strstart .. strstart+2] in the // dictionary, and set hash_head to the head of the hash chain: if (lookahead >= MIN_MATCH) { ins_h = (ins_h << hash_shift ^ window[strstart + MIN_MATCH - 1] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = head[ins_h] & 0xffff; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; } // Find the longest match, discarding those <= prev_length. // At this point we have always match_length < MIN_MATCH if (hash_head != 0L && (strstart - hash_head & 0xffff) <= w_size - MIN_LOOKAHEAD) { // To simplify the code, we prevent matches with the string // of window index 0 (in particular we have to avoid a match // of the string with itself at the start of the input file). if (strategy != JZlib.Z_HUFFMAN_ONLY) { match_length = longest_match(hash_head); } // longest_match() sets match_start } if (match_length >= MIN_MATCH) { // check_match(strstart, match_start, match_length); bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); lookahead -= match_length; // Insert new strings in the hash table only if the match length // is not too large. This saves time but degrades compression. if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) { match_length --; // string at strstart already in hash table do { strstart ++; ins_h = (ins_h << hash_shift ^ window[strstart + MIN_MATCH - 1] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = head[ins_h] & 0xffff; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; // strstart never exceeds WSIZE-MAX_MATCH, so there are // always MIN_MATCH bytes ahead. } while (-- match_length != 0); strstart ++; } else { strstart += match_length; match_length = 0; ins_h = window[strstart] & 0xff; ins_h = (ins_h << hash_shift ^ window[strstart + 1] & 0xff) & hash_mask; // If lookahead < MIN_MATCH, ins_h is garbage, but it does not // matter since it will be recomputed at next deflate call. } } else { // No match, output a literal byte bflush = _tr_tally(0, window[strstart] & 0xff); lookahead --; strstart ++; } if (bflush) { flush_block_only(false); if (strm.avail_out == 0) { return NeedMore; } } } flush_block_only(flush == JZlib.Z_FINISH); if (strm.avail_out == 0) { if (flush == JZlib.Z_FINISH) { return FinishStarted; } else { return NeedMore; } } return flush == JZlib.Z_FINISH? FinishDone : BlockDone; } // Same as above, but achieves better compression. We use a lazy // evaluation for matches: a match is finally adopted only if there is // no better match at the next window position. private int deflate_slow(int flush) { // short hash_head = 0; // head of hash chain int hash_head = 0; // head of hash chain boolean bflush; // set if current block must be flushed // Process the input block. while (true) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the next match, plus MIN_MATCH bytes to insert the // string following the next match. if (lookahead < MIN_LOOKAHEAD) { fill_window(); if (lookahead < MIN_LOOKAHEAD && flush == JZlib.Z_NO_FLUSH) { return NeedMore; } if (lookahead == 0) { break; // flush the current block } } // Insert the string window[strstart .. strstart+2] in the // dictionary, and set hash_head to the head of the hash chain: if (lookahead >= MIN_MATCH) { ins_h = (ins_h << hash_shift ^ window[strstart + MIN_MATCH - 1] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = head[ins_h] & 0xffff; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; } // Find the longest match, discarding those <= prev_length. prev_length = match_length; prev_match = match_start; match_length = MIN_MATCH - 1; if (hash_head != 0 && prev_length < max_lazy_match && (strstart - hash_head & 0xffff) <= w_size - MIN_LOOKAHEAD) { // To simplify the code, we prevent matches with the string // of window index 0 (in particular we have to avoid a match // of the string with itself at the start of the input file). if (strategy != JZlib.Z_HUFFMAN_ONLY) { match_length = longest_match(hash_head); } // longest_match() sets match_start if (match_length <= 5 && (strategy == JZlib.Z_FILTERED || match_length == MIN_MATCH && strstart - match_start > 4096)) { // If prev_match is also MIN_MATCH, match_start is garbage // but we will ignore the current match anyway. match_length = MIN_MATCH - 1; } } // If there was a match at the previous step and the current // match is not better, output the previous match: if (prev_length >= MIN_MATCH && match_length <= prev_length) { int max_insert = strstart + lookahead - MIN_MATCH; // Do not insert strings in hash table beyond this. // check_match(strstart-1, prev_match, prev_length); bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); // Insert in hash table all strings up to the end of the match. // strstart-1 and strstart are already inserted. If there is not // enough lookahead, the last two strings are not inserted in // the hash table. lookahead -= prev_length - 1; prev_length -= 2; do { if (++ strstart <= max_insert) { ins_h = (ins_h << hash_shift ^ window[strstart + MIN_MATCH - 1] & 0xff) & hash_mask; //prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = head[ins_h] & 0xffff; prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; } } while (-- prev_length != 0); match_available = 0; match_length = MIN_MATCH - 1; strstart ++; if (bflush) { flush_block_only(false); if (strm.avail_out == 0) { return NeedMore; } } } else if (match_available != 0) { // If there was no match at the previous position, output a // single literal. If there was a match but the current match // is longer, truncate the previous match to a single literal. bflush = _tr_tally(0, window[strstart - 1] & 0xff); if (bflush) { flush_block_only(false); } strstart ++; lookahead --; if (strm.avail_out == 0) { return NeedMore; } } else { // There is no previous match to compare with, wait for // the next step to decide. match_available = 1; strstart ++; lookahead --; } } if (match_available != 0) { _tr_tally(0, window[strstart - 1] & 0xff); match_available = 0; } flush_block_only(flush == JZlib.Z_FINISH); if (strm.avail_out == 0) { if (flush == JZlib.Z_FINISH) { return FinishStarted; } else { return NeedMore; } } return flush == JZlib.Z_FINISH? FinishDone : BlockDone; } private int longest_match(int cur_match) { int chain_length = max_chain_length; // max hash chain length int scan = strstart; // current string int match; // matched string int len; // length of current match int best_len = prev_length; // best match length so far int limit = strstart > w_size - MIN_LOOKAHEAD? strstart - (w_size - MIN_LOOKAHEAD) : 0; int nice_match = this.nice_match; // Stop when cur_match becomes <= limit. To simplify the code, // we prevent matches with the string of window index 0. int wmask = w_mask; int strend = strstart + MAX_MATCH; byte scan_end1 = window[scan + best_len - 1]; byte scan_end = window[scan + best_len]; // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. // It is easy to get rid of this optimization if necessary. // Do not waste too much time if we already have a good match: if (prev_length >= good_match) { chain_length >>= 2; } // Do not look for matches beyond the end of the input. This is necessary // to make deflate deterministic. if (nice_match > lookahead) { nice_match = lookahead; } do { match = cur_match; // Skip to next match if the match length cannot increase // or if the match length is less than 2: if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan] || window[++ match] != window[scan + 1]) { continue; } // The check at best_len-1 can be removed because it will be made // again later. (This heuristic is not always a win.) // It is not necessary to compare scan[2] and match[2] since they // are always equal when the other bytes match, given that // the hash keys are equal and that HASH_BITS >= 8. scan += 2; match ++; // We check for insufficient lookahead only every 8th comparison; // the 256th check will be made at strstart+258. while (window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && window[++ scan] == window[++ match] && scan < strend) { continue; } len = MAX_MATCH - (strend - scan); scan = strend - MAX_MATCH; if (len > best_len) { match_start = cur_match; best_len = len; if (len >= nice_match) { break; } scan_end1 = window[scan + best_len - 1]; scan_end = window[scan + best_len]; } } while ((cur_match = prev[cur_match & wmask] & 0xffff) > limit && -- chain_length != 0); if (best_len <= lookahead) { return best_len; } return lookahead; } int deflateInit(ZStream strm, int level, int bits, int memLevel, WrapperType wrapperType) { return deflateInit2(strm, level, JZlib.Z_DEFLATED, bits, memLevel, JZlib.Z_DEFAULT_STRATEGY, wrapperType); } private int deflateInit2(ZStream strm, int level, int method, int windowBits, int memLevel, int strategy, WrapperType wrapperType) { if (wrapperType == WrapperType.ZLIB_OR_NONE) { throw new IllegalArgumentException("ZLIB_OR_NONE allowed only for inflate"); } // byte[] my_version=ZLIB_VERSION; // // if (version == null || version[0] != my_version[0] // || stream_size != sizeof(z_stream)) { // return Z_VERSION_ERROR; // } strm.msg = null; if (level == JZlib.Z_DEFAULT_COMPRESSION) { level = 6; } if (windowBits < 0) { // undocumented feature: suppress zlib header throw new IllegalArgumentException("windowBits: " + windowBits); } if (memLevel < 1 || memLevel > JZlib.MAX_MEM_LEVEL || method != JZlib.Z_DEFLATED || windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > JZlib.Z_HUFFMAN_ONLY) { return JZlib.Z_STREAM_ERROR; } strm.dstate = this; this.wrapperType = wrapperType; w_bits = windowBits; w_size = 1 << w_bits; w_mask = w_size - 1; hash_bits = memLevel + 7; hash_size = 1 << hash_bits; hash_mask = hash_size - 1; hash_shift = (hash_bits + MIN_MATCH - 1) / MIN_MATCH; window = new byte[w_size * 2]; prev = new short[w_size]; head = new short[hash_size]; lit_bufsize = 1 << memLevel + 6; // 16K elements by default // We overlay pending_buf and d_buf+l_buf. This works since the average // output size for (length,distance) codes is <= 24 bits. pending_buf = new byte[lit_bufsize * 4]; pending_buf_size = lit_bufsize * 4; d_buf = lit_bufsize / 2; l_buf = (1 + 2) * lit_bufsize; this.level = level; //System.out.println("level="+level); this.strategy = strategy; return deflateReset(strm); } private int deflateReset(ZStream strm) { strm.total_in = strm.total_out = 0; strm.msg = null; // pending = 0; pending_out = 0; wroteTrailer = false; status = wrapperType == WrapperType.NONE? BUSY_STATE : INIT_STATE; strm.adler = Adler32.adler32(0, null, 0, 0); strm.crc32 = 0; gzipUncompressedBytes = 0; last_flush = JZlib.Z_NO_FLUSH; tr_init(); lm_init(); return JZlib.Z_OK; } int deflateEnd() { if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) { return JZlib.Z_STREAM_ERROR; } // Deallocate in reverse order of allocations: pending_buf = null; head = null; prev = null; window = null; // free // dstate=null; return status == BUSY_STATE? JZlib.Z_DATA_ERROR : JZlib.Z_OK; } int deflateParams(ZStream strm, int _level, int _strategy) { int err = JZlib.Z_OK; if (_level == JZlib.Z_DEFAULT_COMPRESSION) { _level = 6; } if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > JZlib.Z_HUFFMAN_ONLY) { return JZlib.Z_STREAM_ERROR; } if (config_table[level].func != config_table[_level].func && strm.total_in != 0) { // Flush the last buffer: err = strm.deflate(JZlib.Z_PARTIAL_FLUSH); } if (level != _level) { level = _level; max_lazy_match = config_table[level].max_lazy; good_match = config_table[level].good_length; nice_match = config_table[level].nice_length; max_chain_length = config_table[level].max_chain; } strategy = _strategy; return err; } int deflateSetDictionary(ZStream strm, byte[] dictionary, int dictLength) { int length = dictLength; int index = 0; if (dictionary == null || status != INIT_STATE) { return JZlib.Z_STREAM_ERROR; } strm.adler = Adler32.adler32(strm.adler, dictionary, 0, dictLength); if (length < MIN_MATCH) { return JZlib.Z_OK; } if (length > w_size - MIN_LOOKAHEAD) { length = w_size - MIN_LOOKAHEAD; index = dictLength - length; // use the tail of the dictionary } System.arraycopy(dictionary, index, window, 0, length); strstart = length; block_start = length; // Insert all strings in the hash table (except for the last two bytes). // s->lookahead stays null, so s->ins_h will be recomputed at the next // call of fill_window. ins_h = window[0] & 0xff; ins_h = (ins_h << hash_shift ^ window[1] & 0xff) & hash_mask; for (int n = 0; n <= length - MIN_MATCH; n ++) { ins_h = (ins_h << hash_shift ^ window[n + MIN_MATCH - 1] & 0xff) & hash_mask; prev[n & w_mask] = head[ins_h]; head[ins_h] = (short) n; } return JZlib.Z_OK; } int deflate(ZStream strm, int flush) { int old_flush; if (flush > JZlib.Z_FINISH || flush < 0) { return JZlib.Z_STREAM_ERROR; } if (strm.next_out == null || strm.next_in == null && strm.avail_in != 0 || status == FINISH_STATE && flush != JZlib.Z_FINISH) { strm.msg = z_errmsg[JZlib.Z_NEED_DICT - JZlib.Z_STREAM_ERROR]; return JZlib.Z_STREAM_ERROR; } if (strm.avail_out == 0) { strm.msg = z_errmsg[JZlib.Z_NEED_DICT - JZlib.Z_BUF_ERROR]; return JZlib.Z_BUF_ERROR; } this.strm = strm; // just in case old_flush = last_flush; last_flush = flush; // Write the zlib header if (status == INIT_STATE) { switch (wrapperType) { case ZLIB: int header = JZlib.Z_DEFLATED + (w_bits - 8 << 4) << 8; int level_flags = (level - 1 & 0xff) >> 1; if (level_flags > 3) { level_flags = 3; } header |= level_flags << 6; if (strstart != 0) { header |= JZlib.PRESET_DICT; } header += 31 - header % 31; putShortMSB(header); // Save the adler32 of the preset dictionary: if (strstart != 0) { putShortMSB((int) (strm.adler >>> 16)); putShortMSB((int) (strm.adler & 0xffff)); } strm.adler = Adler32.adler32(0, null, 0, 0); break; case GZIP: // Identification put_byte((byte) 0x1f); put_byte((byte) 0x8b); // Compression method: DEFLATE put_byte((byte) 8); // Flags put_byte((byte) 0); // MTIME put_byte((byte) 0); put_byte((byte) 0); put_byte((byte) 0); put_byte((byte) 0); // XFL switch (config_table[level].func) { case FAST: put_byte((byte) 4); break; case SLOW: put_byte((byte) 2); break; default: put_byte((byte) 0); break; } // OS put_byte((byte) 255); strm.crc32 = 0; break; } status = BUSY_STATE; } // Flush as much pending output as possible if (pending != 0) { strm.flush_pending(); if (strm.avail_out == 0) { //System.out.println(" avail_out==0"); // Since avail_out is 0, deflate will be called again with // more output space, but possibly with both pending and // avail_in equal to zero. There won't be anything to do, // but this is not an error situation so make sure we // return OK instead of BUF_ERROR at next call of deflate: last_flush = -1; return JZlib.Z_OK; } // Make sure there is something to do and avoid duplicate consecutive // flushes. For repeated and useless calls with Z_FINISH, we keep // returning Z_STREAM_END instead of Z_BUFF_ERROR. } else if (strm.avail_in == 0 && flush <= old_flush && flush != JZlib.Z_FINISH) { strm.msg = z_errmsg[JZlib.Z_NEED_DICT - JZlib.Z_BUF_ERROR]; return JZlib.Z_BUF_ERROR; } // User must not provide more input after the first FINISH: if (status == FINISH_STATE && strm.avail_in != 0) { strm.msg = z_errmsg[JZlib.Z_NEED_DICT - JZlib.Z_BUF_ERROR]; return JZlib.Z_BUF_ERROR; } // Start a new block or continue the current one. int old_next_in_index = strm.next_in_index; try { if (strm.avail_in != 0 || lookahead != 0 || flush != JZlib.Z_NO_FLUSH && status != FINISH_STATE) { int bstate = -1; switch (config_table[level].func) { case STORED: bstate = deflate_stored(flush); break; case FAST: bstate = deflate_fast(flush); break; case SLOW: bstate = deflate_slow(flush); break; default: } if (bstate == FinishStarted || bstate == FinishDone) { status = FINISH_STATE; } if (bstate == NeedMore || bstate == FinishStarted) { if (strm.avail_out == 0) { last_flush = -1; // avoid BUF_ERROR next call, see above } return JZlib.Z_OK; // If flush != Z_NO_FLUSH && avail_out == 0, the next call // of deflate should use the same flush parameter to make sure // that the flush is complete. So we don't have to output an // empty block here, this will be done at next call. This also // ensures that for a very small output buffer, we emit at most // one empty block. } if (bstate == BlockDone) { if (flush == JZlib.Z_PARTIAL_FLUSH) { _tr_align(); } else { // FULL_FLUSH or SYNC_FLUSH _tr_stored_block(0, 0, false); // For a full flush, this empty block will be recognized // as a special marker by inflate_sync(). if (flush == JZlib.Z_FULL_FLUSH) { //state.head[s.hash_size-1]=0; for (int i = 0; i < hash_size/*-1*/; i ++) { head[i] = 0; } } } strm.flush_pending(); if (strm.avail_out == 0) { last_flush = -1; // avoid BUF_ERROR at next call, see above return JZlib.Z_OK; } } } } finally { gzipUncompressedBytes += strm.next_in_index - old_next_in_index; } if (flush != JZlib.Z_FINISH) { return JZlib.Z_OK; } if (wrapperType == WrapperType.NONE || wroteTrailer) { return JZlib.Z_STREAM_END; } switch (wrapperType) { case ZLIB: // Write the zlib trailer (adler32) putShortMSB((int) (strm.adler >>> 16)); putShortMSB((int) (strm.adler & 0xffff)); break; case GZIP: // Write the gzip trailer (CRC32 & ISIZE) put_byte((byte) (strm.crc32 & 0xFF)); put_byte((byte) (strm.crc32 >>> 8 & 0xFF)); put_byte((byte) (strm.crc32 >>> 16 & 0xFF)); put_byte((byte) (strm.crc32 >>> 24 & 0xFF)); put_byte((byte) (gzipUncompressedBytes & 0xFF)); put_byte((byte) (gzipUncompressedBytes >>> 8 & 0xFF)); put_byte((byte) (gzipUncompressedBytes >>> 16 & 0xFF)); put_byte((byte) (gzipUncompressedBytes >>> 24 & 0xFF)); break; } strm.flush_pending(); // If avail_out is zero, the application will call deflate again // to flush the rest. wroteTrailer = true; // write the trailer only once! return pending != 0? JZlib.Z_OK : JZlib.Z_STREAM_END; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/InfBlocks.java000066400000000000000000000563441225554127700312330ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class InfBlocks { // And'ing with mask[n] masks the lower n bits private static final int[] inflate_mask = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff }; // Table for deflate from PKZIP's appnote.txt. private static final int[] border = { // Order of the bit length code lengths 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; private static final int TYPE = 0; // get type bits (3, including end bit) private static final int LENS = 1; // get lengths for stored private static final int STORED = 2; // processing stored block private static final int TABLE = 3; // get table lengths private static final int BTREE = 4; // get bit lengths tree for a dynamic block private static final int DTREE = 5; // get length, distance trees for a dynamic block private static final int CODES = 6; // processing fixed or dynamic block private static final int DRY = 7; // output remaining window bytes private static final int DONE = 8; // finished last block, done private static final int BAD = 9; // ot a data error--stuck here private int mode; // current inflate_block mode private int left; // if STORED, bytes left to copy private int table; // table lengths (14 bits) private int index; // index into blens (or border) private int[] blens; // bit lengths of codes private final int[] bb = new int[1]; // bit length tree depth private final int[] tb = new int[1]; // bit length decoding tree private final InfCodes codes = new InfCodes(); // if CODES, current state private int last; // true if this block is the last block // mode independent information int bitk; // bits in bit buffer int bitb; // bit buffer private int[] hufts; // single malloc for tree space byte[] window; // sliding window final int end; // one byte after sliding window int read; // window read pointer int write; // window write pointer private final Object checkfn; // check function private long check; // check on output private final InfTree inftree = new InfTree(); InfBlocks(ZStream z, Object checkfn, int w) { hufts = new int[JZlib.MANY * 3]; window = new byte[w]; end = w; this.checkfn = checkfn; mode = TYPE; reset(z, null); } void reset(ZStream z, long[] c) { if (c != null) { c[0] = check; } mode = TYPE; bitk = 0; bitb = 0; read = write = 0; if (checkfn != null) { z.adler = check = Adler32.adler32(0L, null, 0, 0); } } int proc(ZStream z, int r) { int t; // temporary storage int b; // bit buffer int k; // bits in bit buffer int p; // input data pointer int n; // bytes available there int q; // output window write pointer int m; // bytes to end of window or read pointer // copy input/output information to locals (UPDATE macro restores) { p = z.next_in_index; n = z.avail_in; b = bitb; k = bitk; } { q = write; m = q < read? read - q - 1 : end - q; } // process input based on current state while (true) { switch (mode) { case TYPE: while (k < 3) { if (n != 0) { r = JZlib.Z_OK; } else { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } t = b & 7; last = t & 1; switch (t >>> 1) { case 0: // stored { b >>>= 3; k -= 3; } t = k & 7; // go to byte boundary { b >>>= t; k -= t; } mode = LENS; // get length of stored block break; case 1: // fixed { int[] bl = new int[1]; int[] bd = new int[1]; int[][] tl = new int[1][]; int[][] td = new int[1][]; InfTree.inflate_trees_fixed(bl, bd, tl, td); codes.init(bl[0], bd[0], tl[0], 0, td[0], 0); } { b >>>= 3; k -= 3; } mode = CODES; break; case 2: // dynamic { b >>>= 3; k -= 3; } mode = TABLE; break; case 3: // illegal { b >>>= 3; k -= 3; } mode = BAD; z.msg = "invalid block type"; r = JZlib.Z_DATA_ERROR; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } break; case LENS: while (k < 32) { if (n != 0) { r = JZlib.Z_OK; } else { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } if ((~b >>> 16 & 0xffff) != (b & 0xffff)) { mode = BAD; z.msg = "invalid stored block lengths"; r = JZlib.Z_DATA_ERROR; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } left = b & 0xffff; b = k = 0; // dump bits mode = left != 0? STORED : last != 0? DRY : TYPE; break; case STORED: if (n == 0) { bitb = b; bitk = k; z.avail_in = 0; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } if (m == 0) { if (q == end && read != 0) { q = 0; m = q < read? read - q - 1 : end - q; } if (m == 0) { write = q; r = inflate_flush(z, r); q = write; m = q < read? read - q - 1 : end - q; if (q == end && read != 0) { q = 0; m = q < read? read - q - 1 : end - q; } if (m == 0) { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } } } r = JZlib.Z_OK; t = left; if (t > n) { t = n; } if (t > m) { t = m; } System.arraycopy(z.next_in, p, window, q, t); p += t; n -= t; q += t; m -= t; if ((left -= t) != 0) { break; } mode = last != 0? DRY : TYPE; break; case TABLE: while (k < 14) { if (n != 0) { r = JZlib.Z_OK; } else { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } table = t = b & 0x3fff; if ((t & 0x1f) > 29 || (t >> 5 & 0x1f) > 29) { mode = BAD; z.msg = "too many length or distance symbols"; r = JZlib.Z_DATA_ERROR; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } t = 258 + (t & 0x1f) + (t >> 5 & 0x1f); if (blens == null || blens.length < t) { blens = new int[t]; } else { for (int i = 0; i < t; i ++) { blens[i] = 0; } } { b >>>= 14; k -= 14; } index = 0; mode = BTREE; case BTREE: while (index < 4 + (table >>> 10)) { while (k < 3) { if (n != 0) { r = JZlib.Z_OK; } else { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } blens[border[index ++]] = b & 7; { b >>>= 3; k -= 3; } } while (index < 19) { blens[border[index ++]] = 0; } bb[0] = 7; t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); if (t != JZlib.Z_OK) { r = t; if (r == JZlib.Z_DATA_ERROR) { blens = null; mode = BAD; } bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } index = 0; mode = DTREE; case DTREE: while (true) { t = table; if (!(index < 258 + (t & 0x1f) + (t >> 5 & 0x1f))) { break; } int i, j, c; t = bb[0]; while (k < t) { if (n != 0) { r = JZlib.Z_OK; } else { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } if (tb[0] == -1) { //System.err.println("null..."); } t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1]; c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2]; if (c < 16) { b >>>= t; k -= t; blens[index ++] = c; } else { // c == 16..18 i = c == 18? 7 : c - 14; j = c == 18? 11 : 3; while (k < t + i) { if (n != 0) { r = JZlib.Z_OK; } else { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } b >>>= t; k -= t; j += b & inflate_mask[i]; b >>>= i; k -= i; i = index; t = table; if (i + j > 258 + (t & 0x1f) + (t >> 5 & 0x1f) || c == 16 && i < 1) { blens = null; mode = BAD; z.msg = "invalid bit length repeat"; r = JZlib.Z_DATA_ERROR; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } c = c == 16? blens[i - 1] : 0; do { blens[i ++] = c; } while (-- j != 0); index = i; } } tb[0] = -1; { int[] bl = new int[1]; int[] bd = new int[1]; int[] tl = new int[1]; int[] td = new int[1]; bl[0] = 9; // must be <= 9 for lookahead assumptions bd[0] = 6; // must be <= 9 for lookahead assumptions t = table; t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + (t >> 5 & 0x1f), blens, bl, bd, tl, td, hufts, z); if (t != JZlib.Z_OK) { if (t == JZlib.Z_DATA_ERROR) { blens = null; mode = BAD; } r = t; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0]); } mode = CODES; case CODES: bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; if ((r = codes.proc(this, z, r)) != JZlib.Z_STREAM_END) { return inflate_flush(z, r); } r = JZlib.Z_OK; p = z.next_in_index; n = z.avail_in; b = bitb; k = bitk; q = write; m = q < read? read - q - 1 : end - q; if (last == 0) { mode = TYPE; break; } mode = DRY; case DRY: write = q; r = inflate_flush(z, r); q = write; if (read != write) { bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } mode = DONE; case DONE: r = JZlib.Z_STREAM_END; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); case BAD: r = JZlib.Z_DATA_ERROR; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); default: r = JZlib.Z_STREAM_ERROR; bitb = b; bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; write = q; return inflate_flush(z, r); } } } void free(ZStream z) { reset(z, null); window = null; hufts = null; //ZFREE(z, s); } void set_dictionary(byte[] d, int start, int n) { System.arraycopy(d, start, window, 0, n); read = write = n; } // Returns true if inflate is currently at the end of a block generated // by Z_SYNC_FLUSH or Z_FULL_FLUSH. int sync_point() { return mode == LENS? 1 : 0; } // copy as much as possible from the sliding window to the output area int inflate_flush(ZStream z, int r) { int n; int p; int q; // local copies of source and destination pointers p = z.next_out_index; q = read; // compute number of bytes to copy as far as end of window n = (q <= write? write : end) - q; if (n > z.avail_out) { n = z.avail_out; } if (n != 0 && r == JZlib.Z_BUF_ERROR) { r = JZlib.Z_OK; } // update counters z.avail_out -= n; z.total_out += n; // update check information if (checkfn != null) { z.adler = check = Adler32.adler32(check, window, q, n); } // copy as far as end of window System.arraycopy(window, q, z.next_out, p, n); p += n; q += n; // see if more to copy at beginning of window if (q == end) { // wrap pointers q = 0; if (write == end) { write = 0; } // compute bytes to copy n = write - q; if (n > z.avail_out) { n = z.avail_out; } if (n != 0 && r == JZlib.Z_BUF_ERROR) { r = JZlib.Z_OK; } // update counters z.avail_out -= n; z.total_out += n; // update check information if (checkfn != null) { z.adler = check = Adler32.adler32(check, window, q, n); } // copy System.arraycopy(window, q, z.next_out, p, n); p += n; q += n; } // update pointers z.next_out_index = p; read = q; // done return r; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/InfCodes.java000066400000000000000000000616651225554127700310550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class InfCodes { private static final int[] inflate_mask = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff }; // waiting for "i:"=input, // "o:"=output, // "x:"=nothing private static final int START = 0; // x: set up for LEN private static final int LEN = 1; // i: get length/literal/eob next private static final int LENEXT = 2; // i: getting length extra (have base) private static final int DIST = 3; // i: get distance next private static final int DISTEXT = 4; // i: getting distance extra private static final int COPY = 5; // o: copying bytes in window, waiting for space private static final int LIT = 6; // o: got literal, waiting for output space private static final int WASH = 7; // o: got eob, possibly still output waiting private static final int END = 8; // x: got eob and all data flushed private static final int BADCODE = 9; // x: got error private int mode; // current inflate_codes mode // mode dependent information private int len; private int[] tree; // pointer into tree private int tree_index; private int need; // bits needed private int lit; // if EXT or COPY, where and how much private int get; // bits to get for extra private int dist; // distance back to copy from private byte lbits; // ltree bits decoded per branch private byte dbits; // dtree bits decoder per branch private int[] ltree; // literal/length/eob tree private int ltree_index; // literal/length/eob tree private int[] dtree; // distance tree private int dtree_index; // distance tree void init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) { mode = START; lbits = (byte) bl; dbits = (byte) bd; ltree = tl; ltree_index = tl_index; dtree = td; dtree_index = td_index; tree = null; } int proc(InfBlocks s, ZStream z, int r) { int j; // temporary storage int tindex; // temporary pointer int e; // extra bits or operation int b; // bit buffer int k; // bits in bit buffer int p; // input data pointer int n; // bytes available there int q; // output window write pointer int m; // bytes to end of window or read pointer int f; // pointer to copy strings from // copy input/output information to locals (UPDATE macro restores) p = z.next_in_index; n = z.avail_in; b = s.bitb; k = s.bitk; q = s.write; m = q < s.read? s.read - q - 1 : s.end - q; // process input and output based on current state while (true) { switch (mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN if (m >= 258 && n >= 10) { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z); p = z.next_in_index; n = z.avail_in; b = s.bitb; k = s.bitk; q = s.write; m = q < s.read? s.read - q - 1 : s.end - q; if (r != JZlib.Z_OK) { mode = r == JZlib.Z_STREAM_END? WASH : BADCODE; break; } } need = lbits; tree = ltree; tree_index = ltree_index; mode = LEN; case LEN: // i: get length/literal/eob next j = need; while (k < j) { if (n != 0) { r = JZlib.Z_OK; } else { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } tindex = (tree_index + (b & inflate_mask[j])) * 3; b >>>= tree[tindex + 1]; k -= tree[tindex + 1]; e = tree[tindex]; if (e == 0) { // literal lit = tree[tindex + 2]; mode = LIT; break; } if ((e & 16) != 0) { // length get = e & 15; len = tree[tindex + 2]; mode = LENEXT; break; } if ((e & 64) == 0) { // next table need = e; tree_index = tindex / 3 + tree[tindex + 2]; break; } if ((e & 32) != 0) { // end of block mode = WASH; break; } mode = BADCODE; // invalid code z.msg = "invalid literal/length code"; r = JZlib.Z_DATA_ERROR; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); case LENEXT: // i: getting length extra (have base) j = get; while (k < j) { if (n != 0) { r = JZlib.Z_OK; } else { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } len += b & inflate_mask[j]; b >>= j; k -= j; need = dbits; tree = dtree; tree_index = dtree_index; mode = DIST; case DIST: // i: get distance next j = need; while (k < j) { if (n != 0) { r = JZlib.Z_OK; } else { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } tindex = (tree_index + (b & inflate_mask[j])) * 3; b >>= tree[tindex + 1]; k -= tree[tindex + 1]; e = tree[tindex]; if ((e & 16) != 0) { // distance get = e & 15; dist = tree[tindex + 2]; mode = DISTEXT; break; } if ((e & 64) == 0) { // next table need = e; tree_index = tindex / 3 + tree[tindex + 2]; break; } mode = BADCODE; // invalid code z.msg = "invalid distance code"; r = JZlib.Z_DATA_ERROR; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); case DISTEXT: // i: getting distance extra j = get; while (k < j) { if (n != 0) { r = JZlib.Z_OK; } else { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } dist += b & inflate_mask[j]; b >>= j; k -= j; mode = COPY; case COPY: // o: copying bytes in window, waiting for space f = q - dist; while (f < 0) { // modulo window size-"while" instead f += s.end; // of "if" handles invalid distances } while (len != 0) { if (m == 0) { if (q == s.end && s.read != 0) { q = 0; m = q < s.read? s.read - q - 1 : s.end - q; } if (m == 0) { s.write = q; r = s.inflate_flush(z, r); q = s.write; m = q < s.read? s.read - q - 1 : s.end - q; if (q == s.end && s.read != 0) { q = 0; m = q < s.read? s.read - q - 1 : s.end - q; } if (m == 0) { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } } } s.window[q ++] = s.window[f ++]; m --; if (f == s.end) { f = 0; } len --; } mode = START; break; case LIT: // o: got literal, waiting for output space if (m == 0) { if (q == s.end && s.read != 0) { q = 0; m = q < s.read? s.read - q - 1 : s.end - q; } if (m == 0) { s.write = q; r = s.inflate_flush(z, r); q = s.write; m = q < s.read? s.read - q - 1 : s.end - q; if (q == s.end && s.read != 0) { q = 0; m = q < s.read? s.read - q - 1 : s.end - q; } if (m == 0) { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } } } r = JZlib.Z_OK; s.window[q ++] = (byte) lit; m --; mode = START; break; case WASH: // o: got eob, possibly more output if (k > 7) { // return unused byte, if any k -= 8; n ++; p --; // can always return one } s.write = q; r = s.inflate_flush(z, r); q = s.write; if (s.read != s.write) { s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } mode = END; case END: r = JZlib.Z_STREAM_END; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); case BADCODE: // x: got error r = JZlib.Z_DATA_ERROR; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); default: r = JZlib.Z_STREAM_ERROR; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return s.inflate_flush(z, r); } } } // Called with number of bytes left to write in window at least 258 // (the maximum string length) and number of input bytes available // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. static int inflate_fast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InfBlocks s, ZStream z) { int t; // temporary pointer int[] tp; // temporary pointer int tp_index; // temporary pointer int e; // extra bits or operation int b; // bit buffer int k; // bits in bit buffer int p; // input data pointer int n; // bytes available there int q; // output window write pointer int m; // bytes to end of window or read pointer int ml; // mask for literal/length tree int md; // mask for distance tree int c; // bytes to copy int d; // distance back to copy from int r; // copy source pointer int tp_index_t_3; // (tp_index+t)*3 // load input, output, bit values p = z.next_in_index; n = z.avail_in; b = s.bitb; k = s.bitk; q = s.write; m = q < s.read? s.read - q - 1 : s.end - q; // initialize masks ml = inflate_mask[bl]; md = inflate_mask[bd]; // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code while (k < 20) { // max bits for literal/length code n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } t = b & ml; tp = tl; tp_index = tl_index; tp_index_t_3 = (tp_index + t) * 3; if ((e = tp[tp_index_t_3]) == 0) { b >>= tp[tp_index_t_3 + 1]; k -= tp[tp_index_t_3 + 1]; s.window[q ++] = (byte) tp[tp_index_t_3 + 2]; m --; continue; } do { b >>= tp[tp_index_t_3 + 1]; k -= tp[tp_index_t_3 + 1]; if ((e & 16) != 0) { e &= 15; c = tp[tp_index_t_3 + 2] + (b & inflate_mask[e]); b >>= e; k -= e; // decode distance base of block to copy while (k < 15) { // max bits for distance code n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } t = b & md; tp = td; tp_index = td_index; tp_index_t_3 = (tp_index + t) * 3; e = tp[tp_index_t_3]; do { b >>= tp[tp_index_t_3 + 1]; k -= tp[tp_index_t_3 + 1]; if ((e & 16) != 0) { // get extra bits to add to distance base e &= 15; while (k < e) { // get extra bits (up to 13) n --; b |= (z.next_in[p ++] & 0xff) << k; k += 8; } d = tp[tp_index_t_3 + 2] + (b & inflate_mask[e]); b >>= e; k -= e; // do the copy m -= c; if (q >= d) { // offset before dest // just copy r = q - d; if (q - r > 0 && 2 > q - r) { s.window[q ++] = s.window[r ++]; // minimum count is three, s.window[q ++] = s.window[r ++]; // so unroll loop a little c -= 2; } else { System.arraycopy(s.window, r, s.window, q, 2); q += 2; r += 2; c -= 2; } } else { // else offset after destination r = q - d; do { r += s.end; // force pointer in window } while (r < 0); // covers invalid distances e = s.end - r; if (c > e) { // if source crosses, c -= e; // wrapped copy if (q - r > 0 && e > q - r) { do { s.window[q ++] = s.window[r ++]; } while (-- e != 0); } else { System.arraycopy(s.window, r, s.window, q, e); q += e; r += e; } r = 0; // copy rest from start of window } } // copy all or what's left if (q - r > 0 && c > q - r) { do { s.window[q ++] = s.window[r ++]; } while (-- c != 0); } else { System.arraycopy(s.window, r, s.window, q, c); q += c; r += c; } break; } else if ((e & 64) == 0) { t += tp[tp_index_t_3 + 2]; t += b & inflate_mask[e]; tp_index_t_3 = (tp_index + t) * 3; e = tp[tp_index_t_3]; } else { z.msg = "invalid distance code"; c = z.avail_in - n; c = k >> 3 < c? k >> 3 : c; n += c; p -= c; k -= c << 3; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return JZlib.Z_DATA_ERROR; } } while (true); break; } if ((e & 64) == 0) { t += tp[tp_index_t_3 + 2]; t += b & inflate_mask[e]; tp_index_t_3 = (tp_index + t) * 3; if ((e = tp[tp_index_t_3]) == 0) { b >>= tp[tp_index_t_3 + 1]; k -= tp[tp_index_t_3 + 1]; s.window[q ++] = (byte) tp[tp_index_t_3 + 2]; m --; break; } } else if ((e & 32) != 0) { c = z.avail_in - n; c = k >> 3 < c? k >> 3 : c; n += c; p -= c; k -= c << 3; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return JZlib.Z_STREAM_END; } else { z.msg = "invalid literal/length code"; c = z.avail_in - n; c = k >> 3 < c? k >> 3 : c; n += c; p -= c; k -= c << 3; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return JZlib.Z_DATA_ERROR; } } while (true); } while (m >= 258 && n >= 10); // not enough input or output--restore pointers and return c = z.avail_in - n; c = k >> 3 < c? k >> 3 : c; n += c; p -= c; k -= c << 3; s.bitb = b; s.bitk = k; z.avail_in = n; z.total_in += p - z.next_in_index; z.next_in_index = p; s.write = q; return JZlib.Z_OK; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/InfTree.java000066400000000000000000000525421225554127700307110ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class InfTree { static final int fixed_bl = 9; static final int fixed_bd = 5; static final int[] fixed_tl = { 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255 }; static final int[] fixed_td = { 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 }; // Tables for deflate from PKZIP's appnote.txt. static final int[] cplens = { // Copy lengths for literal codes 257..285 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; // see note #13 above about 258 static final int[] cplext = { // Extra bits for literal codes 257..285 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid }; static final int[] cpdist = { // Copy offsets for distance codes 0..29 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }; static final int[] cpdext = { // Extra bits for distance codes 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; // If BMAX needs to be larger than 16, then h and x[] should be uLong. static final int BMAX = 15; // maximum bit length of any code private int[] hn; // hufts used in space private int[] v; // work area for huft_build private int[] c; // bit length count table private int[] r; // table entry for structure assignment private int[] u; // table stack private int[] x; // bit offsets, then code stack private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX) int bindex, int n, // number of codes (assumed <= 288) int s, // number of simple-valued codes (0..s-1) int[] d, // list of base values for non-simple codes int[] e, // list of extra bits for non-simple codes int[] t, // result: starting table int[] m, // maximum lookup bits, returns actual int[] hp, // space for trees int[] hn, // hufts used in space int[] v // working area: values in order of bit length ) { // Given a list of code lengths and a maximum table size, make a set of // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR // if the given code set is incomplete (the tables are still built in this // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of // lengths), or Z_MEM_ERROR if not enough memory. int a; // counter for codes of length k int f; // i repeats in table every f entries int g; // maximum code length int h; // table level int i; // counter, current code int j; // counter int k; // number of bits in current code int l; // bits per table (returned in m) int mask; // (1 << w) - 1, to avoid cc -O bug on HP int p; // pointer into c[], b[], or v[] int q; // points to current table int w; // bits before this table == (l * h) int xp; // pointer into x int y; // number of dummy codes added int z; // number of entries in current table // Generate counts for each bit length p = 0; i = n; do { c[b[bindex + p]] ++; p ++; i --; // assume all entries <= BMAX } while (i != 0); if (c[0] == n) { // null input--all zero length codes t[0] = -1; m[0] = 0; return JZlib.Z_OK; } // Find minimum and maximum length, bound *m by those l = m[0]; for (j = 1; j <= BMAX; j ++) { if (c[j] != 0) { break; } } k = j; // minimum code length if (l < j) { l = j; } for (i = BMAX; i != 0; i --) { if (c[i] != 0) { break; } } g = i; // maximum code length if (l > i) { l = i; } m[0] = l; // Adjust last length count to fill out codes, if needed for (y = 1 << j; j < i; j ++, y <<= 1) { if ((y -= c[j]) < 0) { return JZlib.Z_DATA_ERROR; } } if ((y -= c[i]) < 0) { return JZlib.Z_DATA_ERROR; } c[i] += y; // Generate starting offsets into the value table for each length x[1] = j = 0; p = 1; xp = 2; while (-- i != 0) { // note that i == g from above x[xp] = j += c[p]; xp ++; p ++; } // Make a table of values in order of bit lengths i = 0; p = 0; do { if ((j = b[bindex + p]) != 0) { v[x[j] ++] = i; } p ++; } while (++ i < n); n = x[g]; // set n to length of v // Generate the Huffman codes and for each, make the table entries x[0] = i = 0; // first Huffman code is zero p = 0; // grab values in bit order h = -1; // no tables yet--level -1 w = -l; // bits decoded == (l * h) u[0] = 0; // just to keep compilers happy q = 0; // ditto z = 0; // ditto // go through the bit lengths (k already is bits in shortest code) for (; k <= g; k ++) { a = c[k]; while (a -- != 0) { // here i is the Huffman code of length k bits for value *p // make tables up to required level while (k > w + l) { h ++; w += l; // previous table always l bits // compute minimum size table less than or equal to l bits z = g - w; z = z > l? l : z; // table size upper limit if ((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table // too few codes for k-w bit table f -= a + 1; // deduct codes from patterns left xp = k; if (j < z) { while (++ j < z) { // try smaller tables up to z bits if ((f <<= 1) <= c[++ xp]) { break; // enough codes to use up j bits } f -= c[xp]; // else deduct codes from patterns } } } z = 1 << j; // table entries for j-bit table // allocate new table if (hn[0] + z > JZlib.MANY) { // (note: doesn't matter for fixed) return JZlib.Z_DATA_ERROR; // overflow of MANY } u[h] = q = /*hp+*/hn[0]; // DEBUG hn[0] += z; // connect to last table, if there is one if (h != 0) { x[h] = i; // save pattern for backing up r[0] = (byte) j; // bits in this table r[1] = (byte) l; // bits to dump before this table j = i >>> w - l; r[2] = q - u[h - 1] - j; // offset to this table System.arraycopy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table } else { t[0] = q; // first table is returned result } } // set up table entry in r r[1] = (byte) (k - w); if (p >= n) { r[0] = 128 + 64; // out of values--invalid code } else if (v[p] < s) { r[0] = (byte) (v[p] < 256? 0 : 32 + 64); // 256 is end-of-block r[2] = v[p ++]; // simple code is just the value } else { r[0] = (byte) (e[v[p] - s] + 16 + 64); // non-simple--look up in lists r[2] = d[v[p ++] - s]; } // fill code-like entries with r f = 1 << k - w; for (j = i >>> w; j < z; j += f) { System.arraycopy(r, 0, hp, (q + j) * 3, 3); } // backwards increment the k-bit code i for (j = 1 << k - 1; (i & j) != 0; j >>>= 1) { i ^= j; } i ^= j; // backup over finished tables mask = (1 << w) - 1; // needed on HP, cc -O bug while ((i & mask) != x[h]) { h --; // don't need to update q w -= l; mask = (1 << w) - 1; } } } // Return Z_BUF_ERROR if we were given an incomplete table return y != 0 && g != 1? JZlib.Z_BUF_ERROR : JZlib.Z_OK; } int inflate_trees_bits(int[] c, // 19 code lengths int[] bb, // bits tree desired/actual depth int[] tb, // bits tree result int[] hp, // space for trees ZStream z // for messages ) { int result; initWorkArea(19); hn[0] = 0; result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); if (result == JZlib.Z_DATA_ERROR) { z.msg = "oversubscribed dynamic bit lengths tree"; } else if (result == JZlib.Z_BUF_ERROR || bb[0] == 0) { z.msg = "incomplete dynamic bit lengths tree"; result = JZlib.Z_DATA_ERROR; } return result; } int inflate_trees_dynamic(int nl, // number of literal/length codes int nd, // number of distance codes int[] c, // that many (total) code lengths int[] bl, // literal desired/actual bit depth int[] bd, // distance desired/actual bit depth int[] tl, // literal/length tree result int[] td, // distance tree result int[] hp, // space for trees ZStream z // for messages ) { int result; // build literal/length tree initWorkArea(288); hn[0] = 0; result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); if (result != JZlib.Z_OK || bl[0] == 0) { if (result == JZlib.Z_DATA_ERROR) { z.msg = "oversubscribed literal/length tree"; } else if (result != JZlib.Z_MEM_ERROR) { z.msg = "incomplete literal/length tree"; result = JZlib.Z_DATA_ERROR; } return result; } // build distance tree initWorkArea(288); result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); if (result != JZlib.Z_OK || bd[0] == 0 && nl > 257) { if (result == JZlib.Z_DATA_ERROR) { z.msg = "oversubscribed distance tree"; } else if (result == JZlib.Z_BUF_ERROR) { z.msg = "incomplete distance tree"; result = JZlib.Z_DATA_ERROR; } else if (result != JZlib.Z_MEM_ERROR) { z.msg = "empty distance tree with lengths"; result = JZlib.Z_DATA_ERROR; } return result; } return JZlib.Z_OK; } static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth int[] bd, //distance desired/actual bit depth int[][] tl, //literal/length tree result int[][] td //distance tree result ) { bl[0] = fixed_bl; bd[0] = fixed_bd; tl[0] = fixed_tl; td[0] = fixed_td; return JZlib.Z_OK; } private void initWorkArea(int vsize) { if (hn == null) { hn = new int[1]; v = new int[vsize]; c = new int[BMAX + 1]; r = new int[3]; u = new int[BMAX]; x = new int[BMAX + 1]; } else { if (v.length < vsize) { v = new int[vsize]; } else { for (int i = 0; i < vsize; i ++) { v[i] = 0; } } for (int i = 0; i < BMAX + 1; i ++) { c[i] = 0; } for (int i = 0; i < 3; i ++) { r[i] = 0; } // for(int i=0; istate); return JZlib.Z_OK; } int inflateInit(ZStream z, int w, WrapperType wrapperType) { z.msg = null; blocks = null; this.wrapperType = wrapperType; if (w < 0) { throw new IllegalArgumentException("w: " + w); } // set window size if (w < 8 || w > 15) { inflateEnd(z); return JZlib.Z_STREAM_ERROR; } wbits = w; z.istate.blocks = new InfBlocks( z, z.istate.wrapperType == WrapperType.NONE? null : this, 1 << w); // reset state inflateReset(z); return JZlib.Z_OK; } int inflate(ZStream z, int f) { int r; int b; if (z == null || z.istate == null || z.next_in == null) { return JZlib.Z_STREAM_ERROR; } f = f == JZlib.Z_FINISH? JZlib.Z_BUF_ERROR : JZlib.Z_OK; r = JZlib.Z_BUF_ERROR; while (true) { //System.out.println("mode: "+z.istate.mode); switch (z.istate.mode) { case METHOD: if (z.avail_in == 0) { return r; } // Switch from zlib to none if necessary. if (z.istate.wrapperType == WrapperType.ZLIB_OR_NONE) { if ((z.next_in[z.next_in_index] & 0xf) != JZlib.Z_DEFLATED || (z.next_in[z.next_in_index] >> 4) + 8 > z.istate.wbits) { z.istate.wrapperType = WrapperType.NONE; z.istate.mode = BLOCKS; break; } else { z.istate.wrapperType = WrapperType.ZLIB; } } r = f; z.avail_in --; z.total_in ++; if (((z.istate.method = z.next_in[z.next_in_index ++]) & 0xf) != JZlib.Z_DEFLATED) { z.istate.mode = BAD; z.msg = "unknown compression method"; z.istate.marker = 5; // can't try inflateSync break; } if ((z.istate.method >> 4) + 8 > z.istate.wbits) { z.istate.mode = BAD; z.msg = "invalid window size"; z.istate.marker = 5; // can't try inflateSync break; } z.istate.mode = FLAG; case FLAG: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; b = z.next_in[z.next_in_index ++] & 0xff; if (((z.istate.method << 8) + b) % 31 != 0) { z.istate.mode = BAD; z.msg = "incorrect header check"; z.istate.marker = 5; // can't try inflateSync break; } if ((b & JZlib.PRESET_DICT) == 0) { z.istate.mode = BLOCKS; break; } z.istate.mode = DICT4; case DICT4: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need = (z.next_in[z.next_in_index ++] & 0xff) << 24 & 0xff000000L; z.istate.mode = DICT3; case DICT3: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 16 & 0xff0000L; z.istate.mode = DICT2; case DICT2: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 8 & 0xff00L; z.istate.mode = DICT1; case DICT1: if (z.avail_in == 0) { return r; } z.avail_in --; z.total_in ++; z.istate.need += z.next_in[z.next_in_index ++] & 0xffL; z.adler = z.istate.need; z.istate.mode = DICT0; return JZlib.Z_NEED_DICT; case DICT0: z.istate.mode = BAD; z.msg = "need dictionary"; z.istate.marker = 0; // can try inflateSync return JZlib.Z_STREAM_ERROR; case BLOCKS: int old_next_out_index = z.next_out_index; try { r = z.istate.blocks.proc(z, r); if (r == JZlib.Z_DATA_ERROR) { z.istate.mode = BAD; z.istate.marker = 0; // can try inflateSync break; } if (r == JZlib.Z_OK) { r = f; } if (r != JZlib.Z_STREAM_END) { return r; } r = f; z.istate.blocks.reset(z, z.istate.was); } finally { int decompressedBytes = z.next_out_index - old_next_out_index; gzipUncompressedBytes += decompressedBytes; z.crc32 = CRC32.crc32(z.crc32, z.next_out, old_next_out_index, decompressedBytes); } if (z.istate.wrapperType == WrapperType.NONE) { z.istate.mode = DONE; break; } if (z.istate.wrapperType == WrapperType.ZLIB) { z.istate.mode = CHECK4; } else if (z.istate.wrapperType == WrapperType.GZIP) { gzipCRC32 = 0; gzipISize = 0; gzipBytesToRead = 4; z.istate.mode = GZIP_CRC32; break; } else { z.istate.mode = BAD; z.msg = "unexpected state"; z.istate.marker = 0; break; } case CHECK4: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need = (z.next_in[z.next_in_index ++] & 0xff) << 24 & 0xff000000L; z.istate.mode = CHECK3; case CHECK3: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 16 & 0xff0000L; z.istate.mode = CHECK2; case CHECK2: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need += (z.next_in[z.next_in_index ++] & 0xff) << 8 & 0xff00L; z.istate.mode = CHECK1; case CHECK1: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.istate.need += z.next_in[z.next_in_index ++] & 0xffL; if ((int) z.istate.was[0] != (int) z.istate.need) { z.istate.mode = BAD; z.msg = "incorrect data check"; z.istate.marker = 5; // can't try inflateSync break; } z.istate.mode = DONE; case DONE: return JZlib.Z_STREAM_END; case BAD: return JZlib.Z_DATA_ERROR; case GZIP_ID1: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; if ((z.next_in[z.next_in_index ++] & 0xff) != 31) { z.istate.mode = BAD; z.msg = "not a gzip stream"; z.istate.marker = 5; // can't try inflateSync break; } z.istate.mode = GZIP_ID2; case GZIP_ID2: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; if ((z.next_in[z.next_in_index ++] & 0xff) != 139) { z.istate.mode = BAD; z.msg = "not a gzip stream"; z.istate.marker = 5; // can't try inflateSync break; } z.istate.mode = GZIP_CM; case GZIP_CM: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; if ((z.next_in[z.next_in_index ++] & 0xff) != JZlib.Z_DEFLATED) { z.istate.mode = BAD; z.msg = "unknown compression method"; z.istate.marker = 5; // can't try inflateSync break; } z.istate.mode = GZIP_FLG; case GZIP_FLG: if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; gzipFlag = z.next_in[z.next_in_index ++] & 0xff; if ((gzipFlag & 0xE2) != 0) { z.istate.mode = BAD; z.msg = "unsupported flag"; z.istate.marker = 5; // can't try inflateSync break; } gzipBytesToRead = 6; z.istate.mode = GZIP_MTIME_XFL_OS; case GZIP_MTIME_XFL_OS: while (gzipBytesToRead > 0) { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.next_in_index ++; gzipBytesToRead --; } z.istate.mode = GZIP_XLEN; gzipXLen = 0; gzipBytesToRead = 2; case GZIP_XLEN: if ((gzipFlag & 4) != 0) { while (gzipBytesToRead > 0) { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; gzipXLen |= (z.next_in[z.next_in_index ++] & 0xff) << (1 - gzipBytesToRead) * 8; gzipBytesToRead --; } gzipBytesToRead = gzipXLen; z.istate.mode = GZIP_FEXTRA; } else { z.istate.mode = GZIP_FNAME; break; } case GZIP_FEXTRA: while (gzipBytesToRead > 0) { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.next_in_index ++; gzipBytesToRead --; } z.istate.mode = GZIP_FNAME; case GZIP_FNAME: if ((gzipFlag & 8) != 0) { do { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; } while (z.next_in[z.next_in_index ++] != 0); } z.istate.mode = GZIP_FCOMMENT; case GZIP_FCOMMENT: if ((gzipFlag & 16) != 0) { do { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; } while (z.next_in[z.next_in_index ++] != 0); } gzipBytesToRead = 2; z.istate.mode = GZIP_FHCRC; case GZIP_FHCRC: if ((gzipFlag & 2) != 0) { while (gzipBytesToRead > 0) { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; z.next_in_index ++; gzipBytesToRead --; } } z.istate.mode = BLOCKS; break; case GZIP_CRC32: while (gzipBytesToRead > 0) { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; gzipBytesToRead --; z.istate.gzipCRC32 |= (z.next_in[z.next_in_index ++] & 0xff) << (3 - gzipBytesToRead) * 8; } if (z.crc32 != z.istate.gzipCRC32) { z.istate.mode = BAD; z.msg = "incorrect CRC32 checksum"; z.istate.marker = 5; // can't try inflateSync break; } gzipBytesToRead = 4; z.istate.mode = GZIP_ISIZE; case GZIP_ISIZE: while (gzipBytesToRead > 0) { if (z.avail_in == 0) { return r; } r = f; z.avail_in --; z.total_in ++; gzipBytesToRead --; z.istate.gzipISize |= (z.next_in[z.next_in_index ++] & 0xff) << (3 - gzipBytesToRead) * 8; } if (gzipUncompressedBytes != z.istate.gzipISize) { z.istate.mode = BAD; z.msg = "incorrect ISIZE checksum"; z.istate.marker = 5; // can't try inflateSync break; } z.istate.mode = DONE; break; default: return JZlib.Z_STREAM_ERROR; } } } static int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength) { int index = 0; int length = dictLength; if (z == null || z.istate == null || z.istate.mode != DICT0) { return JZlib.Z_STREAM_ERROR; } if (Adler32.adler32(1L, dictionary, 0, dictLength) != z.adler) { return JZlib.Z_DATA_ERROR; } z.adler = Adler32.adler32(0, null, 0, 0); if (length >= 1 << z.istate.wbits) { length = (1 << z.istate.wbits) - 1; index = dictLength - length; } z.istate.blocks.set_dictionary(dictionary, index, length); z.istate.mode = BLOCKS; return JZlib.Z_OK; } private static final byte[] mark = { (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff }; int inflateSync(ZStream z) { int n; // number of bytes to look at int p; // pointer to bytes int m; // number of marker bytes found in a row long r, w; // temporaries to save total_in and total_out // set up if (z == null || z.istate == null) { return JZlib.Z_STREAM_ERROR; } if (z.istate.mode != BAD) { z.istate.mode = BAD; z.istate.marker = 0; } if ((n = z.avail_in) == 0) { return JZlib.Z_BUF_ERROR; } p = z.next_in_index; m = z.istate.marker; // search while (n != 0 && m < 4) { if (z.next_in[p] == mark[m]) { m ++; } else if (z.next_in[p] != 0) { m = 0; } else { m = 4 - m; } p ++; n --; } // restore z.total_in += p - z.next_in_index; z.next_in_index = p; z.avail_in = n; z.istate.marker = m; // return no joy or set up to restart on a new block if (m != 4) { return JZlib.Z_DATA_ERROR; } r = z.total_in; w = z.total_out; inflateReset(z); z.total_in = r; z.total_out = w; z.istate.mode = BLOCKS; return JZlib.Z_OK; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/JZlib.java000066400000000000000000000107501225554127700303620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; public final class JZlib { // wrapper types public static final Enum W_NONE = WrapperType.NONE; public static final Enum W_ZLIB = WrapperType.ZLIB; public static final Enum W_GZIP = WrapperType.GZIP; public static final Enum W_ZLIB_OR_NONE = WrapperType.ZLIB_OR_NONE; // compression levels public static final int Z_NO_COMPRESSION = 0; public static final int Z_BEST_SPEED = 1; public static final int Z_BEST_COMPRESSION = 9; public static final int Z_DEFAULT_COMPRESSION = -1; // compression strategy public static final int Z_FILTERED = 1; public static final int Z_HUFFMAN_ONLY = 2; public static final int Z_DEFAULT_STRATEGY = 0; // flush method public static final int Z_NO_FLUSH = 0; public static final int Z_PARTIAL_FLUSH = 1; public static final int Z_SYNC_FLUSH = 2; public static final int Z_FULL_FLUSH = 3; public static final int Z_FINISH = 4; // return codes public static final int Z_OK = 0; public static final int Z_STREAM_END = 1; public static final int Z_NEED_DICT = 2; public static final int Z_ERRNO = -1; public static final int Z_STREAM_ERROR = -2; public static final int Z_DATA_ERROR = -3; public static final int Z_MEM_ERROR = -4; public static final int Z_BUF_ERROR = -5; public static final int Z_VERSION_ERROR = -6; // internal stuff static final int Z_DEFLATED = 8; static final int MAX_MEM_LEVEL = 9; static final int DEF_MEM_LEVEL = 8; static final int MAX_WBITS = 15; // 32K LZ77 window static final int DEF_WBITS = MAX_WBITS; static final int MAX_BITS = 15; static final int PRESET_DICT = 0x20; // preset dictionary flag in zlib header static final int MANY = 1440; static final int BL_CODES = 19; static final int D_CODES = 30; static final int LITERALS = 256; static final int LENGTH_CODES = 29; static final int L_CODES = LITERALS + 1 + LENGTH_CODES; static final int HEAP_SIZE = 2 * L_CODES + 1; // Bit length codes must not exceed MAX_BL_BITS bits static final int MAX_BL_BITS = 7; enum WrapperType { NONE, ZLIB, GZIP, ZLIB_OR_NONE } private JZlib() { // Utility class } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/StaticTree.java000066400000000000000000000142301225554127700314140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class StaticTree { static final short[] static_ltree = { 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8, 2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, 8, 106, 8, 234, 8, 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8, 22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8, 30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, 8, 126, 8, 254, 8, 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8, 5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9, 51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9, 23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9, 223, 9, 479, 9, 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8 }; static final short[] static_dtree = { 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5, 1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 }; static final StaticTree static_l_desc = new StaticTree(static_ltree, Tree.extra_lbits, JZlib.LITERALS + 1, JZlib.L_CODES, JZlib.MAX_BITS); static final StaticTree static_d_desc = new StaticTree(static_dtree, Tree.extra_dbits, 0, JZlib.D_CODES, JZlib.MAX_BITS); static final StaticTree static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, JZlib.BL_CODES, JZlib.MAX_BL_BITS); final short[] static_tree; // static tree or null final int[] extra_bits; // extra bits for each code or null final int extra_base; // base index for extra_bits final int elems; // max number of elements in the tree final int max_length; // max bit length for the codes StaticTree(short[] static_tree, int[] extra_bits, int extra_base, int elems, int max_length) { this.static_tree = static_tree; this.extra_bits = extra_bits; this.extra_base = extra_base; this.elems = elems; this.max_length = max_length; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/Tree.java000066400000000000000000000374541225554127700302610ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; final class Tree { // extra bits for each length code static final int[] extra_lbits = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; // extra bits for each distance code static final int[] extra_dbits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; // extra bits for each bit length code static final int[] extra_blbits = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; static final byte[] bl_order = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static final byte[] _dist_code = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; static final byte[] _length_code = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; static final int[] base_length = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; static final int[] base_dist = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; // Mapping from a distance to a distance code. dist is the distance - 1 and // must not have side effects. _dist_code[256] and _dist_code[257] are never // used. static int d_code(int dist) { return dist < 256? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; } short[] dyn_tree; // the dynamic tree int max_code; // largest code with non zero frequency StaticTree stat_desc; // the corresponding static tree // Compute the optimal bit lengths for a tree and update the total bit length // for the current block. // IN assertion: the fields freq and dad are set, heap[heap_max] and // above are the tree nodes sorted by increasing frequency. // OUT assertions: the field len is set to the optimal bit length, the // array bl_count contains the frequencies for each bit length. // The length opt_len is updated; static_len is also updated if stree is // not null. private void gen_bitlen(Deflate s) { short[] tree = dyn_tree; short[] stree = stat_desc.static_tree; int[] extra = stat_desc.extra_bits; int base = stat_desc.extra_base; int max_length = stat_desc.max_length; int h; // heap index int n, m; // iterate over the tree elements int bits; // bit length int xbits; // extra bits short f; // frequency int overflow = 0; // number of elements with bit length too large for (bits = 0; bits <= JZlib.MAX_BITS; bits ++) { s.bl_count[bits] = 0; } // In a first pass, compute the optimal bit lengths (which may // overflow in the case of the bit length tree). tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap for (h = s.heap_max + 1; h < JZlib.HEAP_SIZE; h ++) { n = s.heap[h]; bits = tree[tree[n * 2 + 1] * 2 + 1] + 1; if (bits > max_length) { bits = max_length; overflow ++; } tree[n * 2 + 1] = (short) bits; // We overwrite tree[n*2+1] which is no longer needed if (n > max_code) { continue; // not a leaf node } s.bl_count[bits] ++; xbits = 0; if (n >= base) { xbits = extra[n - base]; } f = tree[n * 2]; s.opt_len += f * (bits + xbits); if (stree != null) { s.static_len += f * (stree[n * 2 + 1] + xbits); } } if (overflow == 0) { return; } // This happens for example on obj2 and pic of the Calgary corpus // Find the first bit length which could increase: do { bits = max_length - 1; while (s.bl_count[bits] == 0) { bits --; } s.bl_count[bits] --; // move one leaf down the tree s.bl_count[bits + 1] += 2; // move one overflow item as its brother s.bl_count[max_length] --; // The brother of the overflow item also moves one step up, // but this does not affect bl_count[max_length] overflow -= 2; } while (overflow > 0); for (bits = max_length; bits != 0; bits --) { n = s.bl_count[bits]; while (n != 0) { m = s.heap[-- h]; if (m > max_code) { continue; } if (tree[m * 2 + 1] != bits) { s.opt_len += ((long) bits - tree[m * 2 + 1]) * tree[m * 2]; tree[m * 2 + 1] = (short) bits; } n --; } } } // Construct one Huffman tree and assigns the code bit strings and lengths. // Update the total bit length for the current block. // IN assertion: the field freq is set for all tree elements. // OUT assertions: the fields len and code are set to the optimal bit length // and corresponding code. The length opt_len is updated; static_len is // also updated if stree is not null. The field max_code is set. void build_tree(Deflate s) { short[] tree = dyn_tree; short[] stree = stat_desc.static_tree; int elems = stat_desc.elems; int n, m; // iterate over heap elements int max_code = -1; // largest code with non zero frequency int node; // new node being created // Construct the initial heap, with least frequent element in // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. // heap[0] is not used. s.heap_len = 0; s.heap_max = JZlib.HEAP_SIZE; for (n = 0; n < elems; n ++) { if (tree[n * 2] != 0) { s.heap[++ s.heap_len] = max_code = n; s.depth[n] = 0; } else { tree[n * 2 + 1] = 0; } } // The pkzip format requires that at least one distance code exists, // and that at least one bit should be sent even if there is only one // possible code. So to avoid special checks later on we force at least // two codes of non zero frequency. while (s.heap_len < 2) { node = s.heap[++ s.heap_len] = max_code < 2? ++ max_code : 0; tree[node * 2] = 1; s.depth[node] = 0; s.opt_len --; if (stree != null) { s.static_len -= stree[node * 2 + 1]; // node is 0 or 1 so it does not have extra bits } } this.max_code = max_code; // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, // establish sub-heaps of increasing lengths: for (n = s.heap_len / 2; n >= 1; n --) { s.pqdownheap(tree, n); } // Construct the Huffman tree by repeatedly combining the least two // frequent nodes. node = elems; // next internal node of the tree do { // n = node of least frequency n = s.heap[1]; s.heap[1] = s.heap[s.heap_len --]; s.pqdownheap(tree, 1); m = s.heap[1]; // m = node of next least frequency s.heap[-- s.heap_max] = n; // keep the nodes sorted by frequency s.heap[-- s.heap_max] = m; // Create a new node father of n and m tree[node * 2] = (short) (tree[n * 2] + tree[m * 2]); s.depth[node] = (byte) (Math.max(s.depth[n], s.depth[m]) + 1); tree[n * 2 + 1] = tree[m * 2 + 1] = (short) node; // and insert the new node in the heap s.heap[1] = node ++; s.pqdownheap(tree, 1); } while (s.heap_len >= 2); s.heap[-- s.heap_max] = s.heap[1]; // At this point, the fields freq and dad are set. We can now // generate the bit lengths. gen_bitlen(s); // The field len is now set, we can generate the bit codes gen_codes(tree, max_code, s.bl_count); } // Generate the codes for a given tree and bit counts (which need not be // optimal). // IN assertion: the array bl_count contains the bit length statistics for // the given tree and the field len is set for all tree elements. // OUT assertion: the field code is set for all tree elements of non // zero code length. private static void gen_codes(short[] tree, // the tree to decorate int max_code, // largest code with non zero frequency short[] bl_count // number of codes at each bit length ) { short[] next_code = new short[JZlib.MAX_BITS + 1]; // next code value for each bit length short code = 0; // running code value int bits; // bit index int n; // code index // The distribution counts are first used to generate the code values // without bit reversal. for (bits = 1; bits <= JZlib.MAX_BITS; bits ++) { next_code[bits] = code = (short) (code + bl_count[bits - 1] << 1); } // Check that the bit counts in bl_count are consistent. The last code // must be all ones. //Assert (code + bl_count[MAX_BITS]-1 == (1<>>= 1; res <<= 1; } while (-- len > 0); return res >>> 1; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/ZStream.java000066400000000000000000000176511225554127700307440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /* Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ package org.jboss.netty.util.internal.jzlib; import org.jboss.netty.util.internal.jzlib.JZlib.WrapperType; public final class ZStream { public byte[] next_in; // next input byte public int next_in_index; public int avail_in; // number of bytes available at next_in public long total_in; // total nb of input bytes read so far public byte[] next_out; // next output byte should be put there public int next_out_index; public int avail_out; // remaining free space at next_out public long total_out; // total nb of bytes output so far public String msg; Deflate dstate; Inflate istate; long adler; int crc32; public int inflateInit() { return inflateInit(JZlib.DEF_WBITS); } public int inflateInit(Enum wrapperType) { return inflateInit(JZlib.DEF_WBITS, wrapperType); } public int inflateInit(int w) { return inflateInit(w, WrapperType.ZLIB); } public int inflateInit(int w, @SuppressWarnings("rawtypes") Enum wrapperType) { istate = new Inflate(); return istate.inflateInit(this, w, (WrapperType) wrapperType); } public int inflate(int f) { if (istate == null) { return JZlib.Z_STREAM_ERROR; } return istate.inflate(this, f); } public int inflateEnd() { if (istate == null) { return JZlib.Z_STREAM_ERROR; } int ret = istate.inflateEnd(this); istate = null; return ret; } public int inflateSync() { if (istate == null) { return JZlib.Z_STREAM_ERROR; } return istate.inflateSync(this); } public int inflateSetDictionary(byte[] dictionary, int dictLength) { if (istate == null) { return JZlib.Z_STREAM_ERROR; } return Inflate.inflateSetDictionary(this, dictionary, dictLength); } public int deflateInit(int level) { return deflateInit(level, JZlib.MAX_WBITS); } public int deflateInit(int level, Enum wrapperType) { return deflateInit(level, JZlib.MAX_WBITS, wrapperType); } public int deflateInit(int level, int bits) { return deflateInit(level, bits, WrapperType.ZLIB); } public int deflateInit(int level, int bits, Enum wrapperType) { return deflateInit(level, bits, JZlib.DEF_MEM_LEVEL, wrapperType); } public int deflateInit(int level, int bits, int memLevel, @SuppressWarnings("rawtypes") Enum wrapperType) { dstate = new Deflate(); return dstate.deflateInit(this, level, bits, memLevel, (WrapperType) wrapperType); } public int deflate(int flush) { if (dstate == null) { return JZlib.Z_STREAM_ERROR; } return dstate.deflate(this, flush); } public int deflateEnd() { if (dstate == null) { return JZlib.Z_STREAM_ERROR; } int ret = dstate.deflateEnd(); dstate = null; return ret; } public int deflateParams(int level, int strategy) { if (dstate == null) { return JZlib.Z_STREAM_ERROR; } return dstate.deflateParams(this, level, strategy); } public int deflateSetDictionary(byte[] dictionary, int dictLength) { if (dstate == null) { return JZlib.Z_STREAM_ERROR; } return dstate.deflateSetDictionary(this, dictionary, dictLength); } // Flush as much pending output as possible. All deflate() output goes // through this function so some applications may wish to modify it // to avoid allocating a large strm->next_out buffer and copying into it. // (See also read_buf()). void flush_pending() { int len = dstate.pending; if (len > avail_out) { len = avail_out; } if (len == 0) { return; } if (dstate.pending_buf.length <= dstate.pending_out || next_out.length <= next_out_index || dstate.pending_buf.length < dstate.pending_out + len || next_out.length < next_out_index + len) { System.out.println(dstate.pending_buf.length + ", " + dstate.pending_out + ", " + next_out.length + ", " + next_out_index + ", " + len); System.out.println("avail_out=" + avail_out); } System.arraycopy(dstate.pending_buf, dstate.pending_out, next_out, next_out_index, len); next_out_index += len; dstate.pending_out += len; total_out += len; avail_out -= len; dstate.pending -= len; if (dstate.pending == 0) { dstate.pending_out = 0; } } // Read a new buffer from the current input stream, update the adler32 // and total number of bytes read. All deflate() input goes through // this function so some applications may wish to modify it to avoid // allocating a large strm->next_in buffer and copying from it. // (See also flush_pending()). int read_buf(byte[] buf, int start, int size) { int len = avail_in; if (len > size) { len = size; } if (len == 0) { return 0; } avail_in -= len; switch (dstate.wrapperType) { case ZLIB: adler = Adler32.adler32(adler, next_in, next_in_index, len); break; case GZIP: crc32 = CRC32.crc32(crc32, next_in, next_in_index, len); break; } System.arraycopy(next_in, next_in_index, buf, start, len); next_in_index += len; total_in += len; return len; } public void free() { next_in = null; next_out = null; msg = null; } } netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/jzlib/package-info.java000066400000000000000000000014131225554127700316700ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Internal-use-only utilities which is not allowed to be used * outside Netty. */ package org.jboss.netty.util.internal.jzlib; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/internal/package-info.java000066400000000000000000000014051225554127700305570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Internal-use-only utilities which is not allowed to be used * outside Netty. */ package org.jboss.netty.util.internal; netty-netty-3.9.0.Final/src/main/java/org/jboss/netty/util/package-info.java000066400000000000000000000016121225554127700267430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ /** * Utility classes used across multiple packages. * * @apiviz.exclude * @apiviz.exclude ^java\.(lang|util)\. * @apiviz.exclude \.netty\.(?!util)[a-z0-9]+\. * @apiviz.exclude Util$ * @apiviz.exclude \.EstimatableObjectWrapper$ */ package org.jboss.netty.util; netty-netty-3.9.0.Final/src/main/resources/000077500000000000000000000000001225554127700206165ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/resources/org/000077500000000000000000000000001225554127700214055ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/resources/org/jboss/000077500000000000000000000000001225554127700225255ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/resources/org/jboss/netty/000077500000000000000000000000001225554127700236705ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/resources/org/jboss/netty/container/000077500000000000000000000000001225554127700256525ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/resources/org/jboss/netty/container/spring/000077500000000000000000000000001225554127700271545ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/main/resources/org/jboss/netty/container/spring/beans.xml000066400000000000000000000021371225554127700307710ustar00rootroot00000000000000 netty-netty-3.9.0.Final/src/site/000077500000000000000000000000001225554127700166245ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/site/template.vm000066400000000000000000000021461225554127700210060ustar00rootroot00000000000000#* * Copyright 2011 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. *# $project.name - Redirecting... Please click here if not redirected automatically. netty-netty-3.9.0.Final/src/test/000077500000000000000000000000001225554127700166375ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/000077500000000000000000000000001225554127700175605ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/000077500000000000000000000000001225554127700203475ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/000077500000000000000000000000001225554127700214675ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/000077500000000000000000000000001225554127700226325ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/000077500000000000000000000000001225554127700246475ustar00rootroot00000000000000AbstractSocketClientBootstrapTest.java000066400000000000000000000140351225554127700342470ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipelineException; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.util.DummyHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; /** * An abstract test class to test socket client bootstraps */ public abstract class AbstractSocketClientBootstrapTest { protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test(timeout = 10000) public void testFailedConnectionAttempt() throws Exception { ClientBootstrap bootstrap = new ClientBootstrap(); bootstrap.setFactory(newClientSocketChannelFactory(Executors.newCachedThreadPool())); bootstrap.getPipeline().addLast("dummy", new DummyHandler()); bootstrap.setOption("remoteAddress", new InetSocketAddress("255.255.255.255", 1)); ChannelFuture future = bootstrap.connect(); future.awaitUninterruptibly(); assertFalse(future.isSuccess()); assertTrue(future.getCause() instanceof IOException); bootstrap.releaseExternalResources(); } @Test(timeout = 10000) public void testSuccessfulConnectionAttempt() throws Throwable { ClientBootstrap bootstrap = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); ServerSocketChannel serverSocket = ServerSocketChannel.open(); serverSocket.socket().bind(new InetSocketAddress(0)); try { serverSocket.configureBlocking(false); bootstrap.getPipeline().addLast("dummy", new DummyHandler()); bootstrap.setOption( "remoteAddress", new InetSocketAddress( TestUtil.getLocalHost(), serverSocket.socket().getLocalPort())); ChannelFuture future = bootstrap.connect(); serverSocket.accept(); future.awaitUninterruptibly(); if (future.getCause() != null) { throw future.getCause(); } assertTrue(future.isSuccess()); future.getChannel().close().awaitUninterruptibly(); } finally { try { serverSocket.close(); } catch (IOException e) { // Ignore. } bootstrap.shutdown(); bootstrap.releaseExternalResources(); } } @Test(timeout = 10000) public void testSuccessfulConnectionAttemptWithLocalAddress() throws Throwable { ClientBootstrap bootstrap = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); ServerSocketChannel serverSocket = ServerSocketChannel.open(); serverSocket.socket().bind(new InetSocketAddress(0)); try { serverSocket.configureBlocking(false); bootstrap.getPipeline().addLast("dummy", new DummyHandler()); bootstrap.setOption( "remoteAddress", new InetSocketAddress( TestUtil.getLocalHost(), serverSocket.socket().getLocalPort())); bootstrap.setOption("localAddress", new InetSocketAddress(0)); ChannelFuture future = bootstrap.connect(); serverSocket.accept(); future.awaitUninterruptibly(); if (future.getCause() != null) { throw future.getCause(); } assertTrue(future.isSuccess()); future.getChannel().close().awaitUninterruptibly(); } finally { try { serverSocket.close(); } catch (IOException e) { // Ignore. } bootstrap.shutdown(); bootstrap.releaseExternalResources(); } } @Test(expected = ChannelPipelineException.class) public void testFailedPipelineInitialization() throws Exception { ClientBootstrap bootstrap = new ClientBootstrap(createMock(ChannelFactory.class)); ChannelPipelineFactory pipelineFactory = createMock(ChannelPipelineFactory.class); bootstrap.setPipelineFactory(pipelineFactory); expect(pipelineFactory.getPipeline()).andThrow(new ChannelPipelineException()); replay(pipelineFactory); ChannelFuture future = bootstrap.connect(new InetSocketAddress(TestUtil.getLocalHost(), 1)); future.awaitUninterruptibly(); bootstrap.shutdown(); bootstrap.releaseExternalResources(); } @Test(expected = IllegalStateException.class) public void shouldHaveRemoteAddressOption() { new ClientBootstrap(createMock(ChannelFactory.class)).connect(); } @Test(expected = NullPointerException.class) public void shouldDisallowNullRemoteAddressParameter1() { new ClientBootstrap(createMock(ChannelFactory.class)).connect(null); } @Test(expected = NullPointerException.class) public void shouldDisallowNullRemoteAddressParameter2() { new ClientBootstrap(createMock(ChannelFactory.class)).connect(null, null); } } AbstractSocketServerBootstrapTest.java000066400000000000000000000162701225554127700343020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelException; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineException; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChildChannelStateEvent; import org.jboss.netty.channel.ServerChannelFactory; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.SocketChannelConfig; import org.jboss.netty.util.DummyHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; /** * An abstract test class to test server socket bootstraps */ public abstract class AbstractSocketServerBootstrapTest { private static final boolean BUFSIZE_MODIFIABLE; static { boolean bufSizeModifiable = true; Socket s = new Socket(); try { s.setReceiveBufferSize(1234); try { if (s.getReceiveBufferSize() != 1234) { throw new IllegalStateException(); } } catch (Exception e) { bufSizeModifiable = false; System.err.println( "Socket.getReceiveBufferSize() does not work: " + e); } } catch (Exception e) { bufSizeModifiable = false; System.err.println( "Socket.setReceiveBufferSize() does not work: " + e); } finally { BUFSIZE_MODIFIABLE = bufSizeModifiable; try { s.close(); } catch (IOException e) { // Ignore. } } } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); @Test(timeout = 30000, expected = ChannelException.class) public void testFailedBindAttempt() throws Exception { ServerBootstrap bootstrap = new ServerBootstrap(); final ServerSocket ss = new ServerSocket(0); final int boundPort = ss.getLocalPort(); try { bootstrap.setFactory(newServerSocketChannelFactory(Executors.newCachedThreadPool())); bootstrap.setOption("localAddress", new InetSocketAddress(boundPort)); bootstrap.bind().close().awaitUninterruptibly(); } finally { ss.close(); bootstrap.releaseExternalResources(); } } @Test(timeout = 30000) public void testSuccessfulBindAttempt() throws Exception { ServerBootstrap bootstrap = new ServerBootstrap( newServerSocketChannelFactory(Executors.newCachedThreadPool())); bootstrap.setParentHandler(new ParentChannelHandler()); bootstrap.setOption("localAddress", new InetSocketAddress(0)); bootstrap.setOption("child.receiveBufferSize", 9753); bootstrap.setOption("child.sendBufferSize", 8642); bootstrap.getPipeline().addLast("dummy", new DummyHandler()); Channel channel = bootstrap.bind(); ParentChannelHandler pch = channel.getPipeline().get(ParentChannelHandler.class); Socket socket = null; try { socket = new Socket( TestUtil.getLocalHost(), ((InetSocketAddress) channel.getLocalAddress()).getPort()); // Wait until the connection is open in the server side. while (pch.child == null) { Thread.yield(); } SocketChannelConfig cfg = (SocketChannelConfig) pch.child.getConfig(); if (BUFSIZE_MODIFIABLE) { assertEquals(9753, cfg.getReceiveBufferSize()); assertEquals(8642, cfg.getSendBufferSize()); } } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { // Ignore. } } channel.close().awaitUninterruptibly(); } // Wait until the child connection is closed in the client side. // We do not use Channel.close() to make sure it is closed automatically. while (pch.child.isOpen()) { try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore } } // Wait until all child events are fired. while (pch.result.length() < 2) { try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore } } // Confirm the received child events. assertEquals("12", pch.result.toString()); bootstrap.releaseExternalResources(); } @Test(expected = ChannelPipelineException.class) public void testFailedPipelineInitialization() throws Exception { ClientBootstrap bootstrap = new ClientBootstrap(createMock(ChannelFactory.class)); ChannelPipelineFactory pipelineFactory = createMock(ChannelPipelineFactory.class); bootstrap.setPipelineFactory(pipelineFactory); expect(pipelineFactory.getPipeline()).andThrow(new ChannelPipelineException()); replay(pipelineFactory); bootstrap.connect(new InetSocketAddress(TestUtil.getLocalHost(), 1)); bootstrap.releaseExternalResources(); } @Test(expected = IllegalStateException.class) public void shouldHaveLocalAddressOption() { new ServerBootstrap(createMock(ServerChannelFactory.class)).bind(); } @Test(expected = NullPointerException.class) public void shouldDisallowNullLocalAddressParameter() { new ServerBootstrap(createMock(ServerChannelFactory.class)).bind(null); } private static class ParentChannelHandler extends SimpleChannelUpstreamHandler { volatile Channel child; final StringBuffer result = new StringBuffer(); ParentChannelHandler() { } @Override public void childChannelClosed(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { result.append('2'); } @Override public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { child = e.getChildChannel(); result.append('1'); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/BootstrapOrderedMapTest.java000066400000000000000000000061231225554127700322740ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import static org.junit.Assert.*; import java.util.AbstractMap; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.junit.Test; /** * A test to make sure that a bootstrap can recognize ordered maps */ public class BootstrapOrderedMapTest { @Test public void shouldReturnTrueIfLinkedHashMap() { assertTrue(Bootstrap.isOrderedMap(new LinkedHashMap())); } @Test public void shouldReturnTrueIfMapImplementsOrderedMap() { assertTrue(Bootstrap.isOrderedMap(new DummyOrderedMap())); } @Test public void shouldReturnFalseIfMapHasNoDefaultConstructor() { assertFalse(Bootstrap.isOrderedMap( new MapWithoutDefaultConstructor( new HashMap()))); } @Test public void shouldReturnFalseIfMapIsNotOrdered() { assertFalse(Bootstrap.isOrderedMap(new HashMap())); } @Test public void shouldReturnTrueIfMapIsOrdered() { assertTrue(Bootstrap.isOrderedMap(new UnknownOrderedMap())); } interface OrderedMap { // A tag interface } static class DummyOrderedMap extends AbstractMap implements OrderedMap { private final Map map = new HashMap(); @Override public Set> entrySet() { return map.entrySet(); } } static class MapWithoutDefaultConstructor extends AbstractMap { private final Map map; MapWithoutDefaultConstructor(Map map) { this.map = map; } @Override public Set> entrySet() { return map.entrySet(); } } static class UnknownOrderedMap extends AbstractMap { private final Map map = new LinkedHashMap(); @Override public boolean containsKey(Object key) { return map.containsKey(key); } @Override public int size() { return map.size(); } @Override public V put(K key, V value) { return map.put(key, value); } @Override public Set keySet() { return map.keySet(); } @Override public Set> entrySet() { return map.entrySet(); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/BootstrapTest.java000066400000000000000000000224441225554127700303350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.util.DummyHandler; import org.junit.Test; /** * A bootstrap test */ public class BootstrapTest { @Test(expected = IllegalStateException.class) public void shouldNotReturnNullFactory() { newBootstrap().getFactory(); } @Test(expected = IllegalStateException.class) public void shouldNotAllowInitialFactoryToChange() { new Bootstrap(createMock(ChannelFactory.class)).setFactory(createMock(ChannelFactory.class)); } @Test public void shouldNotAllowFactoryToChangeMoreThanOnce() { Bootstrap b = newBootstrap(); ChannelFactory f = createMock(ChannelFactory.class); b.setFactory(f); assertSame(f, b.getFactory()); try { b.setFactory(createMock(ChannelFactory.class)); fail(); } catch (IllegalStateException e) { // Success. } b.releaseExternalResources(); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullFactory() { newBootstrap().setFactory(null); } @Test public void shouldHaveNonNullInitialPipeline() { assertNotNull(newBootstrap().getPipeline()); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullPipeline() { newBootstrap().setPipeline(null); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullPipelineMap() { newBootstrap().setPipelineAsMap(null); } @Test public void shouldHaveNonNullInitialPipelineFactory() { assertNotNull(new Bootstrap().getPipelineFactory()); } @Test public void shouldUpdatePipelineFactoryIfPipelineIsSet() { Bootstrap b = newBootstrap(); ChannelPipelineFactory oldPipelineFactory = b.getPipelineFactory(); b.setPipeline(createMock(ChannelPipeline.class)); assertNotSame(oldPipelineFactory, b.getPipelineFactory()); b.releaseExternalResources(); } @Test(expected = IllegalStateException.class) public void shouldNotReturnPipelineWhenPipelineFactoryIsSetByUser() { Bootstrap b = newBootstrap(); b.setPipelineFactory(createMock(ChannelPipelineFactory.class)); b.getPipeline(); b.releaseExternalResources(); } @Test(expected = IllegalStateException.class) public void shouldNotReturnPipelineMapWhenPipelineFactoryIsSetByUser() { Bootstrap b = newBootstrap(); b.setPipelineFactory(createMock(ChannelPipelineFactory.class)); b.getPipelineAsMap(); b.releaseExternalResources(); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullPipelineFactory() { newBootstrap().setPipelineFactory(null); } @Test public void shouldHaveInitialEmptyPipelineMap() { assertTrue(newBootstrap().getPipelineAsMap().isEmpty()); } @Test public void shouldReturnOrderedPipelineMap() { Bootstrap b = newBootstrap(); ChannelPipeline p = b.getPipeline(); p.addLast("a", new DummyHandler()); p.addLast("b", new DummyHandler()); p.addLast("c", new DummyHandler()); p.addLast("d", new DummyHandler()); Iterator> m = b.getPipelineAsMap().entrySet().iterator(); Entry e; e = m.next(); assertEquals("a", e.getKey()); assertSame(p.get("a"), e.getValue()); e = m.next(); assertEquals("b", e.getKey()); assertSame(p.get("b"), e.getValue()); e = m.next(); assertEquals("c", e.getKey()); assertSame(p.get("c"), e.getValue()); e = m.next(); assertEquals("d", e.getKey()); assertSame(p.get("d"), e.getValue()); assertFalse(m.hasNext()); b.releaseExternalResources(); } @Test(expected = IllegalArgumentException.class) public void shouldNotAllowUnorderedPipelineMap() { Map m = new HashMap(); m.put("a", new DummyHandler()); m.put("b", new DummyHandler()); m.put("c", new DummyHandler()); m.put("d", new DummyHandler()); Bootstrap b = newBootstrap(); b.setPipelineAsMap(m); b.releaseExternalResources(); } @Test public void shouldHaveOrderedPipelineWhenSetFromMap() { Map m = new LinkedHashMap(); m.put("a", new DummyHandler()); m.put("b", new DummyHandler()); m.put("c", new DummyHandler()); m.put("d", new DummyHandler()); Bootstrap b = newBootstrap(); b.setPipelineAsMap(m); ChannelPipeline p = b.getPipeline(); assertSame(p.getFirst(), m.get("a")); assertEquals("a", p.getContext(p.getFirst()).getName()); p.removeFirst(); assertSame(p.getFirst(), m.get("b")); assertEquals("b", p.getContext(p.getFirst()).getName()); p.removeFirst(); assertSame(p.getFirst(), m.get("c")); assertEquals("c", p.getContext(p.getFirst()).getName()); p.removeFirst(); assertSame(p.getFirst(), m.get("d")); assertEquals("d", p.getContext(p.getFirst()).getName()); p.removeFirst(); try { p.removeFirst(); fail(); } catch (NoSuchElementException e) { // Success. } b.releaseExternalResources(); } @Test public void shouldHaveInitialEmptyOptionMap() { assertTrue(newBootstrap().getOptions().isEmpty()); } @Test public void shouldUpdateOptionMapAsRequested1() { Bootstrap b =new Bootstrap(); b.setOption("s", "x"); b.setOption("b", true); b.setOption("i", 42); Map o = b.getOptions(); assertEquals(3, o.size()); assertEquals("x", o.get("s")); assertEquals(true, o.get("b")); assertEquals(42, o.get("i")); b.releaseExternalResources(); } @Test public void shouldUpdateOptionMapAsRequested2() { Bootstrap b = newBootstrap(); Map o1 = new HashMap(); o1.put("s", "x"); o1.put("b", true); o1.put("i", 42); b.setOptions(o1); Map o2 = b.getOptions(); assertEquals(3, o2.size()); assertEquals("x", o2.get("s")); assertEquals(true, o2.get("b")); assertEquals(42, o2.get("i")); assertNotSame(o1, o2); assertEquals(o1, o2); b.releaseExternalResources(); } @Test public void shouldRemoveOptionIfValueIsNull() { Bootstrap b = newBootstrap(); b.setOption("s", "x"); assertEquals("x", b.getOption("s")); b.setOption("s", null); assertNull(b.getOption("s")); assertTrue(b.getOptions().isEmpty()); b.releaseExternalResources(); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullOptionKeyOnGet() { newBootstrap().getOption(null); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullOptionKeyOnSet() { newBootstrap().setOption(null, "x"); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullOptionMap() { newBootstrap().setOptions(null); } protected Bootstrap newBootstrap() { return new Bootstrap(); } @Test public void testReleaseSharedNotDeadlock() { // create bootstraps final ExecutorService pool = Executors.newFixedThreadPool(2); final ClientBootstrap client = new ClientBootstrap( new NioClientSocketChannelFactory(pool, Executors.newCachedThreadPool())); final ServerBootstrap server = new ServerBootstrap( new NioServerSocketChannelFactory(pool, Executors.newCachedThreadPool())); // release resources client.releaseExternalResources(); server.releaseExternalResources(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/ClientBootstrapTest.java000066400000000000000000000015041225554127700314660ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; public class ClientBootstrapTest extends BootstrapTest { @Override protected ClientBootstrap newBootstrap() { return new ClientBootstrap(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/NioSocketClientBootstrapTest.java000066400000000000000000000022011225554127700333000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; /** * A test for New I/O socket client bootstraps */ public class NioSocketClientBootstrapTest extends AbstractSocketClientBootstrapTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/NioSocketServerBootstrapTest.java000066400000000000000000000022011225554127700333300ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * A test for New I/O socket server bootstraps */ public class NioSocketServerBootstrapTest extends AbstractSocketServerBootstrapTest { @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/OioSocketClientBootstrapTest.java000066400000000000000000000021711225554127700333070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; /** * A test for "Old" I/O socket client bootstraps */ public class OioSocketClientBootstrapTest extends AbstractSocketClientBootstrapTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/OioSocketServerBootstrapTest.java000066400000000000000000000022021225554127700333320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; /** * A socket server bootstrap test for "Old" I/O */ public class OioSocketServerBootstrapTest extends AbstractSocketServerBootstrapTest { @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/bootstrap/ServerBootstrapTest.java000066400000000000000000000052211225554127700315160ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.bootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ServerChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.junit.Test; import java.net.InetSocketAddress; import static org.easymock.EasyMock.createMock; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class ServerBootstrapTest extends BootstrapTest { @Override protected ServerBootstrap newBootstrap() { return new ServerBootstrap(); } @Test(expected = IllegalArgumentException.class) public void shouldOnlyAllowServerChannelFactory() { ServerBootstrap bootstrap = newBootstrap(); bootstrap.setFactory(createMock(ChannelFactory.class)); } @Test @Override public void shouldNotAllowFactoryToChangeMoreThanOnce() { Bootstrap b = newBootstrap(); ChannelFactory f = createMock(ServerChannelFactory.class); b.setFactory(f); assertSame(f, b.getFactory()); try { b.setFactory(createMock(ServerChannelFactory.class)); fail(); } catch (IllegalStateException e) { // Success. } b.releaseExternalResources(); } @Test public void testBindAsync() { ServerBootstrap bootstrap = newBootstrap(); bootstrap.setFactory(new NioServerSocketChannelFactory()); ChannelFuture future = bootstrap.bindAsync(new InetSocketAddress(0)); future.awaitUninterruptibly(); assertTrue(future.isSuccess()); future.getChannel().close().awaitUninterruptibly(); } @Test public void testBind() { ServerBootstrap bootstrap = newBootstrap(); bootstrap.setFactory(new NioServerSocketChannelFactory()); Channel channel = bootstrap.bind(new InetSocketAddress(0)); channel.close().awaitUninterruptibly(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/000077500000000000000000000000001225554127700241035ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/AbstractChannelBufferTest.java000066400000000000000000001714271225554127700320100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Random; import java.util.Set; import org.jboss.netty.util.CharsetUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * An abstract test class for channel buffers */ public abstract class AbstractChannelBufferTest { private static final int CAPACITY = 4096; // Must be even private static final int BLOCK_SIZE = 128; private long seed; private Random random; private ChannelBuffer buffer; protected abstract ChannelBuffer newBuffer(int capacity); protected abstract ChannelBuffer[] components(); protected boolean discardReadBytesDoesNotMoveWritableBytes() { return true; } @Before public void init() { buffer = newBuffer(CAPACITY); seed = System.currentTimeMillis(); random = new Random(seed); } @After public void dispose() { buffer = null; } @Test public void initialState() { assertEquals(CAPACITY, buffer.capacity()); assertEquals(0, buffer.readerIndex()); } @Test(expected = IndexOutOfBoundsException.class) public void readerIndexBoundaryCheck1() { try { buffer.writerIndex(0); } catch (IndexOutOfBoundsException e) { fail(); } buffer.readerIndex(-1); } @Test(expected = IndexOutOfBoundsException.class) public void readerIndexBoundaryCheck2() { try { buffer.writerIndex(buffer.capacity()); } catch (IndexOutOfBoundsException e) { fail(); } buffer.readerIndex(buffer.capacity() + 1); } @Test(expected = IndexOutOfBoundsException.class) public void readerIndexBoundaryCheck3() { try { buffer.writerIndex(CAPACITY / 2); } catch (IndexOutOfBoundsException e) { fail(); } buffer.readerIndex(CAPACITY * 3 / 2); } @Test public void readerIndexBoundaryCheck4() { buffer.writerIndex(0); buffer.readerIndex(0); buffer.writerIndex(buffer.capacity()); buffer.readerIndex(buffer.capacity()); } @Test(expected = IndexOutOfBoundsException.class) public void writerIndexBoundaryCheck1() { buffer.writerIndex(-1); } @Test(expected = IndexOutOfBoundsException.class) public void writerIndexBoundaryCheck2() { try { buffer.writerIndex(CAPACITY); buffer.readerIndex(CAPACITY); } catch (IndexOutOfBoundsException e) { fail(); } buffer.writerIndex(buffer.capacity() + 1); } @Test(expected = IndexOutOfBoundsException.class) public void writerIndexBoundaryCheck3() { try { buffer.writerIndex(CAPACITY); buffer.readerIndex(CAPACITY / 2); } catch (IndexOutOfBoundsException e) { fail(); } buffer.writerIndex(CAPACITY / 4); } @Test public void writerIndexBoundaryCheck4() { buffer.writerIndex(0); buffer.readerIndex(0); buffer.writerIndex(CAPACITY); } @Test(expected = IndexOutOfBoundsException.class) public void getByteBoundaryCheck1() { buffer.getByte(-1); } @Test(expected = IndexOutOfBoundsException.class) public void getByteBoundaryCheck2() { buffer.getByte(buffer.capacity()); } @Test(expected = IndexOutOfBoundsException.class) public void getShortBoundaryCheck1() { buffer.getShort(-1); } @Test(expected = IndexOutOfBoundsException.class) public void getShortBoundaryCheck2() { buffer.getShort(buffer.capacity() - 1); } @Test(expected = IndexOutOfBoundsException.class) public void getMediumBoundaryCheck1() { buffer.getMedium(-1); } @Test(expected = IndexOutOfBoundsException.class) public void getMediumBoundaryCheck2() { buffer.getMedium(buffer.capacity() - 2); } @Test(expected = IndexOutOfBoundsException.class) public void getIntBoundaryCheck1() { buffer.getInt(-1); } @Test(expected = IndexOutOfBoundsException.class) public void getIntBoundaryCheck2() { buffer.getInt(buffer.capacity() - 3); } @Test(expected = IndexOutOfBoundsException.class) public void getLongBoundaryCheck1() { buffer.getLong(-1); } @Test(expected = IndexOutOfBoundsException.class) public void getLongBoundaryCheck2() { buffer.getLong(buffer.capacity() - 7); } @Test(expected = IndexOutOfBoundsException.class) public void getByteArrayBoundaryCheck1() { buffer.getBytes(-1, new byte[0]); } @Test(expected = IndexOutOfBoundsException.class) public void getByteArrayBoundaryCheck2() { buffer.getBytes(-1, new byte[0], 0, 0); } @Test public void getByteArrayBoundaryCheck3() { byte[] dst = new byte[4]; buffer.setInt(0, 0x01020304); try { buffer.getBytes(0, dst, -1, 4); fail(); } catch (IndexOutOfBoundsException e) { // Success } // No partial copy is expected. assertEquals(0, dst[0]); assertEquals(0, dst[1]); assertEquals(0, dst[2]); assertEquals(0, dst[3]); } @Test public void getByteArrayBoundaryCheck4() { byte[] dst = new byte[4]; buffer.setInt(0, 0x01020304); try { buffer.getBytes(0, dst, 1, 4); fail(); } catch (IndexOutOfBoundsException e) { // Success } // No partial copy is expected. assertEquals(0, dst[0]); assertEquals(0, dst[1]); assertEquals(0, dst[2]); assertEquals(0, dst[3]); } @Test(expected = IndexOutOfBoundsException.class) public void getByteBufferBoundaryCheck() { buffer.getBytes(-1, ByteBuffer.allocate(0)); } @Test(expected = IndexOutOfBoundsException.class) public void copyBoundaryCheck1() { buffer.copy(-1, 0); } @Test(expected = IndexOutOfBoundsException.class) public void copyBoundaryCheck2() { buffer.copy(0, buffer.capacity() + 1); } @Test(expected = IndexOutOfBoundsException.class) public void copyBoundaryCheck3() { buffer.copy(buffer.capacity() + 1, 0); } @Test(expected = IndexOutOfBoundsException.class) public void copyBoundaryCheck4() { buffer.copy(buffer.capacity(), 1); } @Test(expected = IndexOutOfBoundsException.class) public void setIndexBoundaryCheck1() { buffer.setIndex(-1, CAPACITY); } @Test(expected = IndexOutOfBoundsException.class) public void setIndexBoundaryCheck2() { buffer.setIndex(CAPACITY / 2, CAPACITY / 4); } @Test(expected = IndexOutOfBoundsException.class) public void setIndexBoundaryCheck3() { buffer.setIndex(0, CAPACITY + 1); } @Test public void getByteBufferState() { ByteBuffer dst = ByteBuffer.allocate(4); dst.position(1); dst.limit(3); buffer.setByte(0, (byte) 1); buffer.setByte(1, (byte) 2); buffer.setByte(2, (byte) 3); buffer.setByte(3, (byte) 4); buffer.getBytes(1, dst); assertEquals(3, dst.position()); assertEquals(3, dst.limit()); dst.clear(); assertEquals(0, dst.get(0)); assertEquals(2, dst.get(1)); assertEquals(3, dst.get(2)); assertEquals(0, dst.get(3)); } @Test(expected = IndexOutOfBoundsException.class) public void getDirectByteBufferBoundaryCheck() { buffer.getBytes(-1, ByteBuffer.allocateDirect(0)); } @Test public void getDirectByteBufferState() { ByteBuffer dst = ByteBuffer.allocateDirect(4); dst.position(1); dst.limit(3); buffer.setByte(0, (byte) 1); buffer.setByte(1, (byte) 2); buffer.setByte(2, (byte) 3); buffer.setByte(3, (byte) 4); buffer.getBytes(1, dst); assertEquals(3, dst.position()); assertEquals(3, dst.limit()); dst.clear(); assertEquals(0, dst.get(0)); assertEquals(2, dst.get(1)); assertEquals(3, dst.get(2)); assertEquals(0, dst.get(3)); } @Test public void testRandomByteAccess() { for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); buffer.setByte(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); assertEquals(value, buffer.getByte(i)); } } @Test public void testRandomUnsignedByteAccess() { for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); buffer.setByte(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i ++) { int value = random.nextInt() & 0xFF; assertEquals(value, buffer.getUnsignedByte(i)); } } @Test public void testRandomShortAccess() { for (int i = 0; i < buffer.capacity() - 1; i += 2) { short value = (short) random.nextInt(); buffer.setShort(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 1; i += 2) { short value = (short) random.nextInt(); assertEquals(value, buffer.getShort(i)); } } @Test public void testRandomUnsignedShortAccess() { for (int i = 0; i < buffer.capacity() - 1; i += 2) { short value = (short) random.nextInt(); buffer.setShort(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 1; i += 2) { int value = random.nextInt() & 0xFFFF; assertEquals(value, buffer.getUnsignedShort(i)); } } @Test public void testRandomMediumAccess() { for (int i = 0; i < buffer.capacity() - 2; i += 3) { int value = random.nextInt(); buffer.setMedium(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 2; i += 3) { int value = random.nextInt() << 8 >> 8; assertEquals(value, buffer.getMedium(i)); } } @Test public void testRandomUnsignedMediumAccess() { for (int i = 0; i < buffer.capacity() - 2; i += 3) { int value = random.nextInt(); buffer.setMedium(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 2; i += 3) { int value = random.nextInt() & 0x00FFFFFF; assertEquals(value, buffer.getUnsignedMedium(i)); } } @Test public void testRandomIntAccess() { for (int i = 0; i < buffer.capacity() - 3; i += 4) { int value = random.nextInt(); buffer.setInt(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 3; i += 4) { int value = random.nextInt(); assertEquals(value, buffer.getInt(i)); } } @Test public void testRandomUnsignedIntAccess() { for (int i = 0; i < buffer.capacity() - 3; i += 4) { int value = random.nextInt(); buffer.setInt(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 3; i += 4) { long value = random.nextInt() & 0xFFFFFFFFL; assertEquals(value, buffer.getUnsignedInt(i)); } } @Test public void testRandomLongAccess() { for (int i = 0; i < buffer.capacity() - 7; i += 8) { long value = random.nextLong(); buffer.setLong(i, value); } random.setSeed(seed); for (int i = 0; i < buffer.capacity() - 7; i += 8) { long value = random.nextLong(); assertEquals(value, buffer.getLong(i)); } } @Test public void testSetZero() { buffer.clear(); while (buffer.writable()) { buffer.writeByte((byte) 0xFF); } for (int i = 0; i < buffer.capacity();) { int length = Math.min(buffer.capacity() - i, random.nextInt(32)); buffer.setZero(i, length); i += length; } for (int i = 0; i < buffer.capacity(); i ++) { assertEquals(0, buffer.getByte(i)); } } @Test public void testSequentialByteAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeByte(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readByte()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testSequentialUnsignedByteAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeByte(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i ++) { int value = random.nextInt() & 0xFF; assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readUnsignedByte()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testSequentialShortAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i += 2) { short value = (short) random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeShort(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i += 2) { short value = (short) random.nextInt(); assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readShort()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testSequentialUnsignedShortAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i += 2) { short value = (short) random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeShort(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i += 2) { int value = random.nextInt() & 0xFFFF; assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readUnsignedShort()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testSequentialMediumAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { int value = random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeMedium(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); assertEquals(buffer.capacity() % 3, buffer.writableBytes()); random.setSeed(seed); for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { int value = random.nextInt() << 8 >> 8; assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readMedium()); } assertEquals(buffer.capacity() / 3 * 3, buffer.readerIndex()); assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); assertEquals(0, buffer.readableBytes()); assertEquals(buffer.capacity() % 3, buffer.writableBytes()); } @Test public void testSequentialUnsignedMediumAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { int value = random.nextInt() & 0x00FFFFFF; assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeMedium(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); assertEquals(buffer.capacity() % 3, buffer.writableBytes()); random.setSeed(seed); for (int i = 0; i < buffer.capacity() / 3 * 3; i += 3) { int value = random.nextInt() & 0x00FFFFFF; assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readUnsignedMedium()); } assertEquals(buffer.capacity() / 3 * 3, buffer.readerIndex()); assertEquals(buffer.capacity() / 3 * 3, buffer.writerIndex()); assertEquals(0, buffer.readableBytes()); assertEquals(buffer.capacity() % 3, buffer.writableBytes()); } @Test public void testSequentialIntAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i += 4) { int value = random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeInt(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i += 4) { int value = random.nextInt(); assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readInt()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testSequentialUnsignedIntAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i += 4) { int value = random.nextInt(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeInt(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i += 4) { long value = random.nextInt() & 0xFFFFFFFFL; assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readUnsignedInt()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testSequentialLongAccess() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i += 8) { long value = random.nextLong(); assertEquals(i, buffer.writerIndex()); assertTrue(buffer.writable()); buffer.writeLong(value); } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.writable()); random.setSeed(seed); for (int i = 0; i < buffer.capacity(); i += 8) { long value = random.nextLong(); assertEquals(i, buffer.readerIndex()); assertTrue(buffer.readable()); assertEquals(value, buffer.readLong()); } assertEquals(buffer.capacity(), buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); assertFalse(buffer.readable()); assertFalse(buffer.writable()); } @Test public void testByteArrayTransfer() { byte[] value = new byte[BLOCK_SIZE * 2]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value); buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); } random.setSeed(seed); byte[] expectedValue = new byte[BLOCK_SIZE * 2]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue); int valueOffset = random.nextInt(BLOCK_SIZE); buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue[j], value[j]); } } } @Test public void testRandomByteArrayTransfer1() { byte[] value = new byte[BLOCK_SIZE]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value); buffer.setBytes(i, value); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); buffer.getBytes(i, value); for (int j = 0; j < BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value[j]); } } } @Test public void testRandomByteArrayTransfer2() { byte[] value = new byte[BLOCK_SIZE * 2]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value); buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); int valueOffset = random.nextInt(BLOCK_SIZE); buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value[j]); } } } @Test public void testRandomHeapBufferTransfer1() { byte[] valueContent = new byte[BLOCK_SIZE]; ChannelBuffer value = wrappedBuffer(valueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); value.setIndex(0, BLOCK_SIZE); buffer.setBytes(i, value); assertEquals(BLOCK_SIZE, value.readerIndex()); assertEquals(BLOCK_SIZE, value.writerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); value.clear(); buffer.getBytes(i, value); assertEquals(0, value.readerIndex()); assertEquals(BLOCK_SIZE, value.writerIndex()); for (int j = 0; j < BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } } } @Test public void testRandomHeapBufferTransfer2() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = wrappedBuffer(valueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); int valueOffset = random.nextInt(BLOCK_SIZE); buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } } } @Test public void testRandomDirectBufferTransfer() { byte[] tmp = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = directBuffer(BLOCK_SIZE * 2); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(tmp); value.setBytes(0, tmp, 0, value.capacity()); buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); } random.setSeed(seed); ChannelBuffer expectedValue = directBuffer(BLOCK_SIZE * 2); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(tmp); expectedValue.setBytes(0, tmp, 0, expectedValue.capacity()); int valueOffset = random.nextInt(BLOCK_SIZE); buffer.getBytes(i, value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } } } @Test public void testRandomByteBufferTransfer() { ByteBuffer value = ByteBuffer.allocate(BLOCK_SIZE * 2); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value.array()); value.clear().position(random.nextInt(BLOCK_SIZE)); value.limit(value.position() + BLOCK_SIZE); buffer.setBytes(i, value); } random.setSeed(seed); ByteBuffer expectedValue = ByteBuffer.allocate(BLOCK_SIZE * 2); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue.array()); int valueOffset = random.nextInt(BLOCK_SIZE); value.clear().position(valueOffset).limit(valueOffset + BLOCK_SIZE); buffer.getBytes(i, value); assertEquals(valueOffset + BLOCK_SIZE, value.position()); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.get(j), value.get(j)); } } } @Test public void testSequentialByteArrayTransfer1() { byte[] value = new byte[BLOCK_SIZE]; buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(value); } random.setSeed(seed); byte[] expectedValue = new byte[BLOCK_SIZE]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); buffer.readBytes(value); for (int j = 0; j < BLOCK_SIZE; j ++) { assertEquals(expectedValue[j], value[j]); } } } @Test public void testSequentialByteArrayTransfer2() { byte[] value = new byte[BLOCK_SIZE * 2]; buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); int readerIndex = random.nextInt(BLOCK_SIZE); buffer.writeBytes(value, readerIndex, BLOCK_SIZE); } random.setSeed(seed); byte[] expectedValue = new byte[BLOCK_SIZE * 2]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue); int valueOffset = random.nextInt(BLOCK_SIZE); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); buffer.readBytes(value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue[j], value[j]); } } } @Test public void testSequentialHeapBufferTransfer1() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = wrappedBuffer(valueContent); buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); assertEquals(0, value.readerIndex()); assertEquals(valueContent.length, value.writerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); int valueOffset = random.nextInt(BLOCK_SIZE); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); buffer.readBytes(value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } assertEquals(0, value.readerIndex()); assertEquals(valueContent.length, value.writerIndex()); } } @Test public void testSequentialHeapBufferTransfer2() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = wrappedBuffer(valueContent); buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); int readerIndex = random.nextInt(BLOCK_SIZE); value.readerIndex(readerIndex); value.writerIndex(readerIndex + BLOCK_SIZE); buffer.writeBytes(value); assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex()); assertEquals(value.writerIndex(), value.readerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); int valueOffset = random.nextInt(BLOCK_SIZE); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); value.readerIndex(valueOffset); value.writerIndex(valueOffset); buffer.readBytes(value, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } assertEquals(valueOffset, value.readerIndex()); assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); } } @Test public void testSequentialDirectBufferTransfer1() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = directBuffer(BLOCK_SIZE * 2); buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); value.setBytes(0, valueContent); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); assertEquals(0, value.readerIndex()); assertEquals(0, value.writerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); int valueOffset = random.nextInt(BLOCK_SIZE); value.setBytes(0, valueContent); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); buffer.readBytes(value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } assertEquals(0, value.readerIndex()); assertEquals(0, value.writerIndex()); } } @Test public void testSequentialDirectBufferTransfer2() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = directBuffer(BLOCK_SIZE * 2); buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); value.setBytes(0, valueContent); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); int readerIndex = random.nextInt(BLOCK_SIZE); value.readerIndex(0); value.writerIndex(readerIndex + BLOCK_SIZE); value.readerIndex(readerIndex); buffer.writeBytes(value); assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex()); assertEquals(value.writerIndex(), value.readerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); value.setBytes(0, valueContent); int valueOffset = random.nextInt(BLOCK_SIZE); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); value.readerIndex(valueOffset); value.writerIndex(valueOffset); buffer.readBytes(value, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } assertEquals(valueOffset, value.readerIndex()); assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); } } @Test public void testSequentialByteBufferBackedHeapBufferTransfer1() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = wrappedBuffer(ByteBuffer.allocate(BLOCK_SIZE * 2)); value.writerIndex(0); buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); value.setBytes(0, valueContent); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE); assertEquals(0, value.readerIndex()); assertEquals(0, value.writerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); int valueOffset = random.nextInt(BLOCK_SIZE); value.setBytes(0, valueContent); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); buffer.readBytes(value, valueOffset, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } assertEquals(0, value.readerIndex()); assertEquals(0, value.writerIndex()); } } @Test public void testSequentialByteBufferBackedHeapBufferTransfer2() { byte[] valueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer value = wrappedBuffer(ByteBuffer.allocate(BLOCK_SIZE * 2)); value.writerIndex(0); buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(valueContent); value.setBytes(0, valueContent); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); int readerIndex = random.nextInt(BLOCK_SIZE); value.readerIndex(0); value.writerIndex(readerIndex + BLOCK_SIZE); value.readerIndex(readerIndex); buffer.writeBytes(value); assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex()); assertEquals(value.writerIndex(), value.readerIndex()); } random.setSeed(seed); byte[] expectedValueContent = new byte[BLOCK_SIZE * 2]; ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValueContent); value.setBytes(0, valueContent); int valueOffset = random.nextInt(BLOCK_SIZE); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); value.readerIndex(valueOffset); value.writerIndex(valueOffset); buffer.readBytes(value, BLOCK_SIZE); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.getByte(j), value.getByte(j)); } assertEquals(valueOffset, value.readerIndex()); assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex()); } } @Test public void testSequentialByteBufferTransfer() { buffer.writerIndex(0); ByteBuffer value = ByteBuffer.allocate(BLOCK_SIZE * 2); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(value.array()); value.clear().position(random.nextInt(BLOCK_SIZE)); value.limit(value.position() + BLOCK_SIZE); buffer.writeBytes(value); } random.setSeed(seed); ByteBuffer expectedValue = ByteBuffer.allocate(BLOCK_SIZE * 2); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue.array()); int valueOffset = random.nextInt(BLOCK_SIZE); value.clear().position(valueOffset).limit(valueOffset + BLOCK_SIZE); buffer.readBytes(value); assertEquals(valueOffset + BLOCK_SIZE, value.position()); for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j ++) { assertEquals(expectedValue.get(j), value.get(j)); } } } @Test public void testSequentialCopiedBufferTransfer1() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { byte[] value = new byte[BLOCK_SIZE]; random.nextBytes(value); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(value); } random.setSeed(seed); byte[] expectedValue = new byte[BLOCK_SIZE]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); ChannelBuffer actualValue = buffer.readBytes(BLOCK_SIZE); assertEquals(wrappedBuffer(expectedValue), actualValue); // Make sure if it is a copied buffer. actualValue.setByte(0, (byte) (actualValue.getByte(0) + 1)); assertFalse(buffer.getByte(i) == actualValue.getByte(0)); } } @Test @SuppressWarnings("deprecation") public void testSequentialCopiedBufferTransfer2() { buffer.clear(); buffer.writeZero(buffer.capacity()); try { buffer.readBytes(ChannelBufferIndexFinder.CR); fail(); } catch (NoSuchElementException e) { // Expected } assertSame(EMPTY_BUFFER, buffer.readBytes(ChannelBufferIndexFinder.NUL)); buffer.clear(); buffer.writeBytes(new byte[] { 1, 2, 3, 4, 0 }); ChannelBuffer copy = buffer.readBytes(ChannelBufferIndexFinder.NUL); assertEquals(wrappedBuffer(new byte[] { 1, 2, 3, 4 }), copy); // Make sure if it is a copied buffer. copy.setByte(0, (byte) (copy.getByte(0) + 1)); assertFalse(buffer.getByte(0) == copy.getByte(0)); } @Test public void testSequentialSlice1() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { byte[] value = new byte[BLOCK_SIZE]; random.nextBytes(value); assertEquals(0, buffer.readerIndex()); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(value); } random.setSeed(seed); byte[] expectedValue = new byte[BLOCK_SIZE]; for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { random.nextBytes(expectedValue); assertEquals(i, buffer.readerIndex()); assertEquals(CAPACITY, buffer.writerIndex()); ChannelBuffer actualValue = buffer.readSlice(BLOCK_SIZE); assertEquals(wrappedBuffer(expectedValue), actualValue); // Make sure if it is a sliced buffer. actualValue.setByte(0, (byte) (actualValue.getByte(0) + 1)); assertEquals(buffer.getByte(i), actualValue.getByte(0)); } } @Test @SuppressWarnings("deprecation") public void testSequentialSlice2() { buffer.clear(); buffer.writeZero(buffer.capacity()); try { buffer.readSlice(ChannelBufferIndexFinder.CR); fail(); } catch (NoSuchElementException e) { // Expected } assertSame(EMPTY_BUFFER, buffer.readSlice(ChannelBufferIndexFinder.NUL)); buffer.clear(); buffer.writeBytes(new byte[] { 1, 2, 3, 4, 0 }); ChannelBuffer slice = buffer.readSlice(ChannelBufferIndexFinder.NUL); assertEquals(wrappedBuffer(new byte[] { 1, 2, 3, 4 }), slice); // Make sure if it is a sliced buffer. slice.setByte(0, (byte) (slice.getByte(0) + 1)); assertEquals(buffer.getByte(0), slice.getByte(0)); } @Test public void testWriteZero() { try { buffer.writeZero(-1); fail(); } catch (IllegalArgumentException e) { // Expected } buffer.clear(); while (buffer.writable()) { buffer.writeByte((byte) 0xFF); } buffer.clear(); for (int i = 0; i < buffer.capacity();) { int length = Math.min(buffer.capacity() - i, random.nextInt(32)); buffer.writeZero(length); i += length; } assertEquals(0, buffer.readerIndex()); assertEquals(buffer.capacity(), buffer.writerIndex()); for (int i = 0; i < buffer.capacity(); i ++) { assertEquals(0, buffer.getByte(i)); } } @Test public void testDiscardReadBytes() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i += 4) { buffer.writeInt(i); } ChannelBuffer copy = copiedBuffer(buffer); // Make sure there's no effect if called when readerIndex is 0. buffer.readerIndex(CAPACITY / 4); buffer.markReaderIndex(); buffer.writerIndex(CAPACITY / 3); buffer.markWriterIndex(); buffer.readerIndex(0); buffer.writerIndex(CAPACITY / 2); buffer.discardReadBytes(); assertEquals(0, buffer.readerIndex()); assertEquals(CAPACITY / 2, buffer.writerIndex()); assertEquals(copy.slice(0, CAPACITY / 2), buffer.slice(0, CAPACITY / 2)); buffer.resetReaderIndex(); assertEquals(CAPACITY / 4, buffer.readerIndex()); buffer.resetWriterIndex(); assertEquals(CAPACITY / 3, buffer.writerIndex()); // Make sure bytes after writerIndex is not copied. buffer.readerIndex(1); buffer.writerIndex(CAPACITY / 2); buffer.discardReadBytes(); assertEquals(0, buffer.readerIndex()); assertEquals(CAPACITY / 2 - 1, buffer.writerIndex()); assertEquals(copy.slice(1, CAPACITY / 2 - 1), buffer.slice(0, CAPACITY / 2 - 1)); if (discardReadBytesDoesNotMoveWritableBytes()) { // If writable bytes were copied, the test should fail to avoid unnecessary memory bandwidth consumption. assertFalse(copy.slice(CAPACITY / 2, CAPACITY / 2).equals(buffer.slice(CAPACITY / 2 - 1, CAPACITY / 2))); } else { assertEquals(copy.slice(CAPACITY / 2, CAPACITY / 2), buffer.slice(CAPACITY / 2 - 1, CAPACITY / 2)); } // Marks also should be relocated. buffer.resetReaderIndex(); assertEquals(CAPACITY / 4 - 1, buffer.readerIndex()); buffer.resetWriterIndex(); assertEquals(CAPACITY / 3 - 1, buffer.writerIndex()); } /** * The similar test case with {@link #testDiscardReadBytes()} but this one * discards a large chunk at once. */ @Test public void testDiscardReadBytes2() { buffer.writerIndex(0); for (int i = 0; i < buffer.capacity(); i ++) { buffer.writeByte((byte) i); } ChannelBuffer copy = copiedBuffer(buffer); // Discard the first (CAPACITY / 2 - 1) bytes. buffer.setIndex(CAPACITY / 2 - 1, CAPACITY - 1); buffer.discardReadBytes(); assertEquals(0, buffer.readerIndex()); assertEquals(CAPACITY / 2, buffer.writerIndex()); for (int i = 0; i < CAPACITY / 2; i ++) { assertEquals(copy.slice(CAPACITY / 2 - 1 + i, CAPACITY / 2 - i), buffer.slice(i, CAPACITY / 2 - i)); } } @Test public void testStreamTransfer1() throws Exception { byte[] expected = new byte[buffer.capacity()]; random.nextBytes(expected); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { ByteArrayInputStream in = new ByteArrayInputStream(expected, i, BLOCK_SIZE); assertEquals(BLOCK_SIZE, buffer.setBytes(i, in, BLOCK_SIZE)); assertEquals(-1, buffer.setBytes(i, in, 0)); } ByteArrayOutputStream out = new ByteArrayOutputStream(); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { buffer.getBytes(i, out, BLOCK_SIZE); } assertTrue(Arrays.equals(expected, out.toByteArray())); } @Test public void testStreamTransfer2() throws Exception { byte[] expected = new byte[buffer.capacity()]; random.nextBytes(expected); buffer.clear(); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { ByteArrayInputStream in = new ByteArrayInputStream(expected, i, BLOCK_SIZE); assertEquals(i, buffer.writerIndex()); buffer.writeBytes(in, BLOCK_SIZE); assertEquals(i + BLOCK_SIZE, buffer.writerIndex()); } ByteArrayOutputStream out = new ByteArrayOutputStream(); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { assertEquals(i, buffer.readerIndex()); buffer.readBytes(out, BLOCK_SIZE); assertEquals(i + BLOCK_SIZE, buffer.readerIndex()); } assertTrue(Arrays.equals(expected, out.toByteArray())); } @Test public void testCopy() { for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); buffer.setByte(i, value); } final int readerIndex = CAPACITY / 3; final int writerIndex = CAPACITY * 2 / 3; buffer.setIndex(readerIndex, writerIndex); // Make sure all properties are copied. ChannelBuffer copy = buffer.copy(); assertEquals(0, copy.readerIndex()); assertEquals(buffer.readableBytes(), copy.writerIndex()); assertEquals(buffer.readableBytes(), copy.capacity()); assertSame(buffer.order(), copy.order()); for (int i = 0; i < copy.capacity(); i ++) { assertEquals(buffer.getByte(i + readerIndex), copy.getByte(i)); } // Make sure the buffer content is independent from each other. buffer.setByte(readerIndex, (byte) (buffer.getByte(readerIndex) + 1)); assertTrue(buffer.getByte(readerIndex) != copy.getByte(0)); copy.setByte(1, (byte) (copy.getByte(1) + 1)); assertTrue(buffer.getByte(readerIndex + 1) != copy.getByte(1)); } @Test public void testDuplicate() { for (int i = 0; i < buffer.capacity(); i ++) { byte value = (byte) random.nextInt(); buffer.setByte(i, value); } final int readerIndex = CAPACITY / 3; final int writerIndex = CAPACITY * 2 / 3; buffer.setIndex(readerIndex, writerIndex); // Make sure all properties are copied. ChannelBuffer duplicate = buffer.duplicate(); assertEquals(buffer.readerIndex(), duplicate.readerIndex()); assertEquals(buffer.writerIndex(), duplicate.writerIndex()); assertEquals(buffer.capacity(), duplicate.capacity()); assertSame(buffer.order(), duplicate.order()); for (int i = 0; i < duplicate.capacity(); i ++) { assertEquals(buffer.getByte(i), duplicate.getByte(i)); } // Make sure the buffer content is shared. buffer.setByte(readerIndex, (byte) (buffer.getByte(readerIndex) + 1)); assertEquals(buffer.getByte(readerIndex), duplicate.getByte(readerIndex)); duplicate.setByte(1, (byte) (duplicate.getByte(1) + 1)); assertEquals(buffer.getByte(1), duplicate.getByte(1)); } @Test public void testSliceEndianness() throws Exception { assertEquals(buffer.order(), buffer.slice(0, buffer.capacity()).order()); assertEquals(buffer.order(), buffer.slice(0, buffer.capacity() - 1).order()); assertEquals(buffer.order(), buffer.slice(1, buffer.capacity() - 1).order()); assertEquals(buffer.order(), buffer.slice(1, buffer.capacity() - 2).order()); } @Test public void testSliceIndex() throws Exception { assertEquals(0, buffer.slice(0, buffer.capacity()).readerIndex()); assertEquals(0, buffer.slice(0, buffer.capacity() - 1).readerIndex()); assertEquals(0, buffer.slice(1, buffer.capacity() - 1).readerIndex()); assertEquals(0, buffer.slice(1, buffer.capacity() - 2).readerIndex()); assertEquals(buffer.capacity(), buffer.slice(0, buffer.capacity()).writerIndex()); assertEquals(buffer.capacity() - 1, buffer.slice(0, buffer.capacity() - 1).writerIndex()); assertEquals(buffer.capacity() - 1, buffer.slice(1, buffer.capacity() - 1).writerIndex()); assertEquals(buffer.capacity() - 2, buffer.slice(1, buffer.capacity() - 2).writerIndex()); } @Test public void testEquals() { assertFalse(buffer.equals(null)); assertFalse(buffer.equals(new Object())); byte[] value = new byte[32]; buffer.setIndex(0, value.length); random.nextBytes(value); buffer.setBytes(0, value); assertEquals(buffer, wrappedBuffer(BIG_ENDIAN, value)); assertEquals(buffer, wrappedBuffer(LITTLE_ENDIAN, value)); value[0] ++; assertFalse(buffer.equals(wrappedBuffer(BIG_ENDIAN, value))); assertFalse(buffer.equals(wrappedBuffer(LITTLE_ENDIAN, value))); } @Test public void testCompareTo() { try { buffer.compareTo(null); fail(); } catch (NullPointerException e) { // Expected } // Fill the random stuff byte[] value = new byte[32]; random.nextBytes(value); // Prevent overflow / underflow if (value[0] == 0) { value[0] ++; } else if (value[0] == -1) { value[0] --; } buffer.setIndex(0, value.length); buffer.setBytes(0, value); assertEquals(0, buffer.compareTo(wrappedBuffer(BIG_ENDIAN, value))); assertEquals(0, buffer.compareTo(wrappedBuffer(LITTLE_ENDIAN, value))); value[0] ++; assertTrue(buffer.compareTo(wrappedBuffer(BIG_ENDIAN, value)) < 0); assertTrue(buffer.compareTo(wrappedBuffer(LITTLE_ENDIAN, value)) < 0); value[0] -= 2; assertTrue(buffer.compareTo(wrappedBuffer(BIG_ENDIAN, value)) > 0); assertTrue(buffer.compareTo(wrappedBuffer(LITTLE_ENDIAN, value)) > 0); value[0] ++; assertTrue(buffer.compareTo(wrappedBuffer(BIG_ENDIAN, value, 0, 31)) > 0); assertTrue(buffer.compareTo(wrappedBuffer(LITTLE_ENDIAN, value, 0, 31)) > 0); assertTrue(buffer.slice(0, 31).compareTo(wrappedBuffer(BIG_ENDIAN, value)) < 0); assertTrue(buffer.slice(0, 31).compareTo(wrappedBuffer(LITTLE_ENDIAN, value)) < 0); } @Test public void testToString() { buffer.clear(); buffer.writeBytes(copiedBuffer("Hello, World!", CharsetUtil.ISO_8859_1)); assertEquals("Hello, World!", buffer.toString(CharsetUtil.ISO_8859_1)); } @Test public void testIndexOf() { buffer.clear(); buffer.writeByte((byte) 1); buffer.writeByte((byte) 2); buffer.writeByte((byte) 3); buffer.writeByte((byte) 2); buffer.writeByte((byte) 1); assertEquals(-1, buffer.indexOf(1, 4, (byte) 1)); assertEquals(-1, buffer.indexOf(4, 1, (byte) 1)); assertEquals(1, buffer.indexOf(1, 4, (byte) 2)); assertEquals(3, buffer.indexOf(4, 1, (byte) 2)); } @Test public void testToByteBuffer1() { byte[] value = new byte[buffer.capacity()]; random.nextBytes(value); buffer.clear(); buffer.writeBytes(value); assertEquals(ByteBuffer.wrap(value), buffer.toByteBuffer()); } @Test public void testToByteBuffer2() { byte[] value = new byte[buffer.capacity()]; random.nextBytes(value); buffer.clear(); buffer.writeBytes(value); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { assertEquals(ByteBuffer.wrap(value, i, BLOCK_SIZE), buffer.toByteBuffer(i, BLOCK_SIZE)); } } @Test public void testToByteBuffer3() { assertEquals(buffer.order(), buffer.toByteBuffer().order()); } @Test public void testToByteBuffers1() { byte[] value = new byte[buffer.capacity()]; random.nextBytes(value); buffer.clear(); buffer.writeBytes(value); ByteBuffer[] nioBuffers = buffer.toByteBuffers(); int length = 0; for (ByteBuffer b: nioBuffers) { length += b.remaining(); } ByteBuffer nioBuffer = ByteBuffer.allocate(length); for (ByteBuffer b: nioBuffers) { nioBuffer.put(b); } nioBuffer.flip(); assertEquals(ByteBuffer.wrap(value), nioBuffer); } @Test public void testToByteBuffers2() { byte[] value = new byte[buffer.capacity()]; random.nextBytes(value); buffer.clear(); buffer.writeBytes(value); for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) { ByteBuffer[] nioBuffers = buffer.toByteBuffers(i, BLOCK_SIZE); ByteBuffer nioBuffer = ByteBuffer.allocate(BLOCK_SIZE); for (ByteBuffer b: nioBuffers) { nioBuffer.put(b); } nioBuffer.flip(); assertEquals(ByteBuffer.wrap(value, i, BLOCK_SIZE), nioBuffer); } } @Test public void testSkipBytes1() { buffer.setIndex(CAPACITY / 4, CAPACITY / 2); buffer.skipBytes(CAPACITY / 4); assertEquals(CAPACITY / 4 * 2, buffer.readerIndex()); try { buffer.skipBytes(CAPACITY / 4 + 1); fail(); } catch (IndexOutOfBoundsException e) { // Expected } // Should remain unchanged. assertEquals(CAPACITY / 4 * 2, buffer.readerIndex()); } @Test @SuppressWarnings("deprecation") public void testSkipBytes2() { buffer.clear(); buffer.writeZero(buffer.capacity()); try { buffer.skipBytes(ChannelBufferIndexFinder.LF); fail(); } catch (NoSuchElementException e) { // Expected } buffer.skipBytes(ChannelBufferIndexFinder.NUL); assertEquals(0, buffer.readerIndex()); buffer.clear(); buffer.writeBytes(new byte[] { 1, 2, 3, 4, 0 }); buffer.skipBytes(ChannelBufferIndexFinder.NUL); assertEquals(4, buffer.readerIndex()); } @Test public void testHashCode() { ChannelBuffer elemA = buffer(15); ChannelBuffer elemB = directBuffer(15); elemA.writeBytes(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }); elemB.writeBytes(new byte[] { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9 }); Set set = new HashSet(); set.add(elemA); set.add(elemB); assertEquals(2, set.size()); assertTrue(set.contains(elemA.copy())); assertTrue(set.contains(elemB.copy())); buffer.clear(); buffer.writeBytes(elemA.duplicate()); assertTrue(set.remove(buffer)); assertFalse(set.contains(elemA)); assertEquals(1, set.size()); buffer.clear(); buffer.writeBytes(elemB.duplicate()); assertTrue(set.remove(buffer)); assertFalse(set.contains(elemB)); assertEquals(0, set.size()); } // Test case for https://github.com/netty/netty/issues/325 @Test public void testDiscardAllReadBytes() { buffer.writerIndex(buffer.capacity()); buffer.readerIndex(buffer.writerIndex()); buffer.discardReadBytes(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/AbstractCompositeChannelBufferTest.java000066400000000000000000000361531225554127700336670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import org.junit.Test; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; /** * An abstract test class for composite channel buffers */ public abstract class AbstractCompositeChannelBufferTest extends AbstractChannelBufferTest { private final ByteOrder order; protected AbstractCompositeChannelBufferTest(ByteOrder order) { if (order == null) { throw new NullPointerException("order"); } this.order = order; } private List buffers; private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffers = new ArrayList(); for (int i = 0; i < length; i += 10) { buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[1])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[2])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[3])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[4])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[5])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[6])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[7])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[8])); buffers.add(EMPTY_BUFFER); buffers.add(wrappedBuffer(order, new byte[9])); buffers.add(EMPTY_BUFFER); } buffer = wrappedBuffer(buffers.toArray(new ChannelBuffer[buffers.size()])); buffer.writerIndex(length); buffer = wrappedBuffer(buffer); assertEquals(length, buffer.capacity()); assertEquals(length, buffer.readableBytes()); assertFalse(buffer.writable()); buffer.writerIndex(0); return buffer; } @Override protected ChannelBuffer[] components() { return buffers.toArray(new ChannelBuffer[buffers.size()]); } // Composite buffer does not waste bandwidth on discardReadBytes, but // the test will fail in strict mode. @Override protected boolean discardReadBytesDoesNotMoveWritableBytes() { return false; } @Test public void testGetBuffer() { CompositeChannelBuffer buf = (CompositeChannelBuffer) wrappedBuffer(new byte[]{1, 2, 3, 4, 5}, new byte[]{4, 5, 6, 7, 8, 9, 26}); //Ensure that a random place will be fine assertEquals(5, buf.getBuffer(2).capacity()); //Loop through each byte byte index = 0; while (index < buf.capacity()) { ChannelBuffer _buf = buf.getBuffer(index++); assertNotNull(_buf); assertTrue(_buf.capacity() > 0); assertNotNull(_buf.getByte(0)); assertNotNull(_buf.getByte(_buf.readableBytes() - 1)); } } @Test public void testDiscardReadBytes3() { ChannelBuffer a, b; a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer( wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 0, 5), wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5, 5)); a.skipBytes(6); a.markReaderIndex(); b.skipBytes(6); b.markReaderIndex(); assertEquals(a.readerIndex(), b.readerIndex()); a.readerIndex(a.readerIndex() - 1); b.readerIndex(b.readerIndex() - 1); assertEquals(a.readerIndex(), b.readerIndex()); a.writerIndex(a.writerIndex() - 1); a.markWriterIndex(); b.writerIndex(b.writerIndex() - 1); b.markWriterIndex(); assertEquals(a.writerIndex(), b.writerIndex()); a.writerIndex(a.writerIndex() + 1); b.writerIndex(b.writerIndex() + 1); assertEquals(a.writerIndex(), b.writerIndex()); assertTrue(ChannelBuffers.equals(a, b)); // now discard a.discardReadBytes(); b.discardReadBytes(); assertEquals(a.readerIndex(), b.readerIndex()); assertEquals(a.writerIndex(), b.writerIndex()); assertTrue(ChannelBuffers.equals(a, b)); a.resetReaderIndex(); b.resetReaderIndex(); assertEquals(a.readerIndex(), b.readerIndex()); a.resetWriterIndex(); b.resetWriterIndex(); assertEquals(a.writerIndex(), b.writerIndex()); assertTrue(ChannelBuffers.equals(a, b)); } @Test public void testCompositeWrappedBuffer() { ChannelBuffer header = dynamicBuffer(order, 12); ChannelBuffer payload = dynamicBuffer(order, 512); header.writeBytes(new byte[12]); payload.writeBytes(new byte[512]); ChannelBuffer buffer = wrappedBuffer(header, payload); assertEquals(12, header.readableBytes()); assertEquals(512, payload.readableBytes()); assertEquals(12 + 512, buffer.readableBytes()); assertEquals(12 + 512, buffer.toByteBuffer(0, 12 + 512).remaining()); } @Test public void testSeveralBuffersEquals() { ChannelBuffer a, b; //XXX Same tests with several buffers in wrappedCheckedBuffer // Different length. a = wrappedBuffer(order, new byte[] { 1 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }), wrappedBuffer(order, new byte[] { 2 })); assertFalse(ChannelBuffers.equals(a, b)); // Same content, same firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }), wrappedBuffer(order, new byte[] { 2 }), wrappedBuffer(order, new byte[] { 3 })); assertTrue(ChannelBuffers.equals(a, b)); // Same content, different firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4 }, 1, 2), wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4 }, 3, 1)); assertTrue(ChannelBuffers.equals(a, b)); // Different content, same firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2 }), wrappedBuffer(order, new byte[] { 4 })); assertFalse(ChannelBuffers.equals(a, b)); // Different content, different firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 4, 5 }, 1, 2), wrappedBuffer(order, new byte[] { 0, 1, 2, 4, 5 }, 3, 1)); assertFalse(ChannelBuffers.equals(a, b)); // Same content, same firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 }), wrappedBuffer(order, new byte[] { 4, 5, 6 }), wrappedBuffer(order, new byte[] { 7, 8, 9, 10 })); assertTrue(ChannelBuffers.equals(a, b)); // Same content, different firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 5), wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5)); assertTrue(ChannelBuffers.equals(a, b)); // Different content, same firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 6 }), wrappedBuffer(order, new byte[] { 7, 8, 5, 9, 10 })); assertFalse(ChannelBuffers.equals(a, b)); // Different content, different firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 5), wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5)); assertFalse(ChannelBuffers.equals(a, b)); } @Test public void testWrappedBuffer() { assertEquals(16, wrappedBuffer(wrappedBuffer(ByteBuffer.allocateDirect(16))).capacity()); assertEquals( wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 })), wrappedBuffer(wrappedBuffer(order, new byte[][] { new byte[] { 1, 2, 3 } }))); assertEquals( wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 })), wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }, new byte[] { 2 }, new byte[] { 3 }))); assertEquals( wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 })), wrappedBuffer(new ChannelBuffer[] { wrappedBuffer(order, new byte[] { 1, 2, 3 }) })); assertEquals( wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 })), wrappedBuffer( wrappedBuffer(order, new byte[] { 1 }), wrappedBuffer(order, new byte[] { 2 }), wrappedBuffer(order, new byte[] { 3 }))); assertEquals( wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 })), wrappedBuffer(wrappedBuffer(new ByteBuffer[] { ByteBuffer.wrap(new byte[] { 1, 2, 3 }) }))); assertEquals( wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 })), wrappedBuffer(wrappedBuffer( ByteBuffer.wrap(new byte[] { 1 }), ByteBuffer.wrap(new byte[] { 2 }), ByteBuffer.wrap(new byte[] { 3 })))); } @Test public void testWrittenBuffersEquals() { //XXX Same tests than testEquals with written AggregateChannelBuffers ChannelBuffer a, b; // Different length. a = wrappedBuffer(order, new byte[] { 1 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }, new byte[1])); // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes( wrappedBuffer(order, new byte[] { 2 })); assertFalse(ChannelBuffers.equals(a, b)); // Same content, same firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }, new byte[2])); // to enable writeBytes b.writerIndex(b.writerIndex() - 2); b.writeBytes( wrappedBuffer(order, new byte[] { 2 })); b.writeBytes(wrappedBuffer(order, new byte[] { 3 })); assertTrue(ChannelBuffers.equals(a, b)); // Same content, different firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4 }, 1, 3)); // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes( wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4 }, 3, 1)); assertTrue(ChannelBuffers.equals(a, b)); // Different content, same firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2 }, new byte[1])); // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes( wrappedBuffer(order, new byte[] { 4 })); assertFalse(ChannelBuffers.equals(a, b)); // Different content, different firstIndex, short length. a = wrappedBuffer(order, new byte[] { 1, 2, 3 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 4, 5 }, 1, 3)); // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes( wrappedBuffer(order, new byte[] { 0, 1, 2, 4, 5 }, 3, 1)); assertFalse(ChannelBuffers.equals(a, b)); // Same content, same firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 }, new byte[7])); // to enable writeBytes b.writerIndex(b.writerIndex() - 7); b.writeBytes( wrappedBuffer(order, new byte[] { 4, 5, 6 })); b.writeBytes( wrappedBuffer(order, new byte[] { 7, 8, 9, 10 })); assertTrue(ChannelBuffers.equals(a, b)); // Same content, different firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 10)); // to enable writeBytes b.writerIndex(b.writerIndex() - 5); b.writeBytes( wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5)); assertTrue(ChannelBuffers.equals(a, b)); // Different content, same firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 6 }, new byte[5])); // to enable writeBytes b.writerIndex(b.writerIndex() - 5); b.writeBytes( wrappedBuffer(order, new byte[] { 7, 8, 5, 9, 10 })); assertFalse(ChannelBuffers.equals(a, b)); // Different content, different firstIndex, long length. a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 10)); // to enable writeBytes b.writerIndex(b.writerIndex() - 5); b.writeBytes( wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5)); assertFalse(ChannelBuffers.equals(a, b)); } // Test for #474 @Test public void testEmptyBuffer() { ChannelBuffer b = wrappedBuffer(order, new byte[] {1,2}, new byte[] {3,4}); b.readBytes(new byte[4]); b.readBytes(new byte[0]); } } BigEndianCompositeChannelBufferTest.java000066400000000000000000000016261225554127700336620ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; /** * Tests big-endian composite channel buffers */ public class BigEndianCompositeChannelBufferTest extends AbstractCompositeChannelBufferTest { public BigEndianCompositeChannelBufferTest() { super(ChannelBuffers.BIG_ENDIAN); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/BigEndianDirectChannelBufferTest.java000066400000000000000000000024131225554127700332040ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import java.nio.ByteOrder; /** * Tests big-endian direct channel buffers */ public class BigEndianDirectChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.directBuffer(ByteOrder.BIG_ENDIAN, length); assertSame(ByteOrder.BIG_ENDIAN, buffer.order()); assertEquals(0, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/BigEndianHeapChannelBufferTest.java000066400000000000000000000025071225554127700326530ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import org.junit.Test; /** * Tests big-endian heap channel buffers */ public class BigEndianHeapChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.buffer(length); assertEquals(0, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new BigEndianHeapChannelBuffer(null); } } ByteBufferBackedHeapChannelBufferTest.java000066400000000000000000000025041225554127700341000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import java.nio.ByteBuffer; import org.junit.Test; /** * Tests ByteBuffer backed heap channel buffers */ public class ByteBufferBackedHeapChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = new ByteBufferBackedChannelBuffer(ByteBuffer.allocate(length)); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new ByteBufferBackedChannelBuffer(null); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/ChannelBufferIndexFinderTest.java000066400000000000000000000062471225554127700324410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; /** * Tests the index-finding capabilities of channel buffers */ public class ChannelBufferIndexFinderTest { @Test public void testForward() { ChannelBuffer buf = ChannelBuffers.copiedBuffer( "abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1); assertEquals(3, buf.indexOf(Integer.MIN_VALUE, buf.capacity(), ChannelBufferIndexFinder.CRLF)); assertEquals(6, buf.indexOf(3, buf.capacity(), ChannelBufferIndexFinder.NOT_CRLF)); assertEquals(9, buf.indexOf(6, buf.capacity(), ChannelBufferIndexFinder.CR)); assertEquals(11, buf.indexOf(9, buf.capacity(), ChannelBufferIndexFinder.NOT_CR)); assertEquals(14, buf.indexOf(11, buf.capacity(), ChannelBufferIndexFinder.LF)); assertEquals(16, buf.indexOf(14, buf.capacity(), ChannelBufferIndexFinder.NOT_LF)); assertEquals(19, buf.indexOf(16, buf.capacity(), ChannelBufferIndexFinder.NUL)); assertEquals(21, buf.indexOf(19, buf.capacity(), ChannelBufferIndexFinder.NOT_NUL)); assertEquals(24, buf.indexOf(21, buf.capacity(), ChannelBufferIndexFinder.LINEAR_WHITESPACE)); assertEquals(28, buf.indexOf(24, buf.capacity(), ChannelBufferIndexFinder.NOT_LINEAR_WHITESPACE)); assertEquals(-1, buf.indexOf(28, buf.capacity(), ChannelBufferIndexFinder.LINEAR_WHITESPACE)); } @Test public void testBackward() { ChannelBuffer buf = ChannelBuffers.copiedBuffer( "abc\r\n\ndef\r\rghi\n\njkl\0\0mno \t\tx", CharsetUtil.ISO_8859_1); assertEquals(27, buf.indexOf(Integer.MAX_VALUE, 0, ChannelBufferIndexFinder.LINEAR_WHITESPACE)); assertEquals(23, buf.indexOf(28, 0, ChannelBufferIndexFinder.NOT_LINEAR_WHITESPACE)); assertEquals(20, buf.indexOf(24, 0, ChannelBufferIndexFinder.NUL)); assertEquals(18, buf.indexOf(21, 0, ChannelBufferIndexFinder.NOT_NUL)); assertEquals(15, buf.indexOf(19, 0, ChannelBufferIndexFinder.LF)); assertEquals(13, buf.indexOf(16, 0, ChannelBufferIndexFinder.NOT_LF)); assertEquals(10, buf.indexOf(14, 0, ChannelBufferIndexFinder.CR)); assertEquals(8, buf.indexOf(11, 0, ChannelBufferIndexFinder.NOT_CR)); assertEquals(5, buf.indexOf(9, 0, ChannelBufferIndexFinder.CRLF)); assertEquals(2, buf.indexOf(6, 0, ChannelBufferIndexFinder.NOT_CRLF)); assertEquals(-1, buf.indexOf(3, 0, ChannelBufferIndexFinder.CRLF)); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/ChannelBufferStreamTest.java000066400000000000000000000121341225554127700314650ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import java.io.EOFException; import org.junit.Test; /** * Tests channel buffer streams */ public class ChannelBufferStreamTest { @Test public void testAll() throws Exception { ChannelBuffer buf = ChannelBuffers.dynamicBuffer(); try { new ChannelBufferOutputStream(null); fail(); } catch (NullPointerException e) { // Expected } ChannelBufferOutputStream out = new ChannelBufferOutputStream(buf); assertSame(buf, out.buffer()); out.writeBoolean(true); out.writeBoolean(false); out.writeByte(42); out.writeByte(224); out.writeBytes("Hello, World!"); out.writeChars("Hello, World"); out.writeChar('!'); out.writeDouble(42.0); out.writeFloat(42.0f); out.writeInt(42); out.writeLong(42); out.writeShort(42); out.writeShort(49152); out.writeUTF("Hello, World!"); out.writeBytes("The first line\r\r\n"); out.write(new byte[0]); out.write(new byte[] { 1, 2, 3, 4 }); out.write(new byte[] { 1, 3, 3, 4 }, 0, 0); out.close(); try { new ChannelBufferInputStream(null); fail(); } catch (NullPointerException e) { // Expected } try { new ChannelBufferInputStream(null, 0); fail(); } catch (NullPointerException e) { // Expected } try { new ChannelBufferInputStream(buf, -1); } catch (IllegalArgumentException e) { // Expected } try { new ChannelBufferInputStream(buf, buf.capacity() + 1); } catch (IndexOutOfBoundsException e) { // Expected } ChannelBufferInputStream in = new ChannelBufferInputStream(buf); assertTrue(in.markSupported()); in.mark(Integer.MAX_VALUE); assertEquals(buf.writerIndex(), in.skip(Long.MAX_VALUE)); assertFalse(buf.readable()); in.reset(); assertEquals(0, buf.readerIndex()); assertEquals(4, in.skip(4)); assertEquals(4, buf.readerIndex()); in.reset(); assertTrue(in.readBoolean()); assertFalse(in.readBoolean()); assertEquals(42, in.readByte()); assertEquals(224, in.readUnsignedByte()); byte[] tmp = new byte[13]; in.readFully(tmp); assertEquals("Hello, World!", new String(tmp, "ISO-8859-1")); assertEquals('H', in.readChar()); assertEquals('e', in.readChar()); assertEquals('l', in.readChar()); assertEquals('l', in.readChar()); assertEquals('o', in.readChar()); assertEquals(',', in.readChar()); assertEquals(' ', in.readChar()); assertEquals('W', in.readChar()); assertEquals('o', in.readChar()); assertEquals('r', in.readChar()); assertEquals('l', in.readChar()); assertEquals('d', in.readChar()); assertEquals('!', in.readChar()); assertEquals(42.0, in.readDouble(), 0.0); assertEquals(42.0f, in.readFloat(), 0.0); assertEquals(42, in.readInt()); assertEquals(42, in.readLong()); assertEquals(42, in.readShort()); assertEquals(49152, in.readUnsignedShort()); assertEquals("Hello, World!", in.readUTF()); assertEquals("The first line", in.readLine()); assertEquals(4, in.read(tmp)); assertEquals(1, tmp[0]); assertEquals(2, tmp[1]); assertEquals(3, tmp[2]); assertEquals(4, tmp[3]); assertEquals(-1, in.read()); assertEquals(-1, in.read(tmp)); try { in.readByte(); fail(); } catch (EOFException e) { // Expected } try { in.readFully(tmp, 0, -1); fail(); } catch (IndexOutOfBoundsException e) { // Expected } try { in.readFully(tmp); fail(); } catch (EOFException e) { // Expected } in.close(); assertEquals(buf.readerIndex(), in.readBytes()); } @Test public void testEmptyReadLine() throws Exception { ChannelBuffer buf = ChannelBuffers.buffer(0); ChannelBufferInputStream in = new ChannelBufferInputStream(buf); String s = in.readLine(); assertEquals(0, s.length()); in.close(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/ChannelBuffersTest.java000066400000000000000000000404271225554127700305020ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import org.easymock.EasyMock; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.ScatteringByteChannel; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; /** * Tests channel buffers */ public class ChannelBuffersTest { @Test public void testCompositeWrappedBuffer() { ChannelBuffer header = dynamicBuffer(12); ChannelBuffer payload = dynamicBuffer(512); header.writeBytes(new byte[12]); payload.writeBytes(new byte[512]); ChannelBuffer buffer = wrappedBuffer(header, payload); assertEquals(12, header.readableBytes()); assertEquals(512, payload.readableBytes()); assertEquals(12 + 512, buffer.readableBytes()); assertEquals(12 + 512, buffer.toByteBuffer(0, 12 + 512).remaining()); } @Test public void testHashCode() { Map map = new LinkedHashMap(); map.put(new byte[0], 1); map.put(new byte[] { 1 }, 32); map.put(new byte[] { 2 }, 33); map.put(new byte[] { 0, 1 }, 962); map.put(new byte[] { 1, 2 }, 994); map.put(new byte[] { 0, 1, 2, 3, 4, 5 }, 63504931); map.put(new byte[] { 6, 7, 8, 9, 0, 1 }, (int) 97180294697L); map.put(new byte[] { -1, -1, -1, (byte) 0xE1 }, 1); for (Entry e: map.entrySet()) { assertEquals( e.getValue().intValue(), ChannelBuffers.hashCode(wrappedBuffer(e.getKey()))); } } @Test public void testEquals() { ChannelBuffer a, b; // Different length. a = wrappedBuffer(new byte[] { 1 }); b = wrappedBuffer(new byte[] { 1, 2 }); assertFalse(ChannelBuffers.equals(a, b)); // Same content, same firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 1, 2, 3 }); assertTrue(ChannelBuffers.equals(a, b)); // Same content, different firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 3); assertTrue(ChannelBuffers.equals(a, b)); // Different content, same firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 1, 2, 4 }); assertFalse(ChannelBuffers.equals(a, b)); // Different content, different firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 3); assertFalse(ChannelBuffers.equals(a, b)); // Same content, same firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); assertTrue(ChannelBuffers.equals(a, b)); // Same content, different firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 10); assertTrue(ChannelBuffers.equals(a, b)); // Different content, same firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 1, 2, 3, 4, 6, 7, 8, 5, 9, 10 }); assertFalse(ChannelBuffers.equals(a, b)); // Different content, different firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 10); assertFalse(ChannelBuffers.equals(a, b)); } @Test public void testCompare() { List expected = new ArrayList(); expected.add(wrappedBuffer(new byte[] { 1 })); expected.add(wrappedBuffer(new byte[] { 1, 2 })); expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })); expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 })); expected.add(wrappedBuffer(new byte[] { 2 })); expected.add(wrappedBuffer(new byte[] { 2, 3 })); expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 })); expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 })); expected.add(wrappedBuffer(new byte[] { 2, 3, 4 }, 1, 1)); expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4 }, 2, 2)); expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, 1, 10)); expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, 2, 12)); expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5 }, 2, 1)); expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5 }, 3, 2)); expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, 2, 10)); expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, 3, 12)); for (int i = 0; i < expected.size(); i ++) { for (int j = 0; j < expected.size(); j ++) { if (i == j) { assertEquals(0, compare(expected.get(i), expected.get(j))); } else if (i < j) { assertTrue(compare(expected.get(i), expected.get(j)) < 0); } else { assertTrue(compare(expected.get(i), expected.get(j)) > 0); } } } } @Test public void shouldReturnEmptyBufferWhenLengthIsZero() { assertSame(EMPTY_BUFFER, buffer(0)); assertSame(EMPTY_BUFFER, buffer(LITTLE_ENDIAN, 0)); assertSame(EMPTY_BUFFER, directBuffer(0)); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0])); assertSame(EMPTY_BUFFER, wrappedBuffer(LITTLE_ENDIAN, new byte[0])); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 0, 0)); assertSame(EMPTY_BUFFER, wrappedBuffer(LITTLE_ENDIAN, new byte[8], 0, 0)); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[8], 8, 0)); assertSame(EMPTY_BUFFER, wrappedBuffer(LITTLE_ENDIAN, new byte[8], 8, 0)); assertSame(EMPTY_BUFFER, wrappedBuffer(ByteBuffer.allocateDirect(0))); assertSame(EMPTY_BUFFER, wrappedBuffer(EMPTY_BUFFER)); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[0][])); assertSame(EMPTY_BUFFER, wrappedBuffer(new byte[][] { new byte[0] })); assertSame(EMPTY_BUFFER, wrappedBuffer(new ByteBuffer[0])); assertSame(EMPTY_BUFFER, wrappedBuffer(new ByteBuffer[] { ByteBuffer.allocate(0) })); assertSame(EMPTY_BUFFER, wrappedBuffer(ByteBuffer.allocate(0), ByteBuffer.allocate(0))); assertSame(EMPTY_BUFFER, wrappedBuffer(new ChannelBuffer[0])); assertSame(EMPTY_BUFFER, wrappedBuffer(new ChannelBuffer[] { buffer(0) })); assertSame(EMPTY_BUFFER, wrappedBuffer(buffer(0), buffer(0))); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0])); assertSame(EMPTY_BUFFER, copiedBuffer(LITTLE_ENDIAN, new byte[0])); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 0, 0)); assertSame(EMPTY_BUFFER, copiedBuffer(LITTLE_ENDIAN, new byte[8], 0, 0)); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[8], 8, 0)); assertSame(EMPTY_BUFFER, copiedBuffer(LITTLE_ENDIAN, new byte[8], 8, 0)); assertSame(EMPTY_BUFFER, copiedBuffer(ByteBuffer.allocateDirect(0))); assertSame(EMPTY_BUFFER, copiedBuffer(EMPTY_BUFFER)); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[0][])); assertSame(EMPTY_BUFFER, copiedBuffer(new byte[][] { new byte[0] })); assertSame(EMPTY_BUFFER, copiedBuffer(new ByteBuffer[0])); assertSame(EMPTY_BUFFER, copiedBuffer(new ByteBuffer[] { ByteBuffer.allocate(0) })); assertSame(EMPTY_BUFFER, copiedBuffer(ByteBuffer.allocate(0), ByteBuffer.allocate(0))); assertSame(EMPTY_BUFFER, copiedBuffer(new ChannelBuffer[0])); assertSame(EMPTY_BUFFER, copiedBuffer(new ChannelBuffer[] { buffer(0) })); assertSame(EMPTY_BUFFER, copiedBuffer(buffer(0), buffer(0))); } @Test public void testCompare2() { assertTrue(compare( wrappedBuffer(new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}), wrappedBuffer(new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00})) > 0); assertTrue(compare( wrappedBuffer(new byte[]{(byte) 0xFF}), wrappedBuffer(new byte[]{(byte) 0x00})) > 0); } @Test(expected = NullPointerException.class) public void shouldDisallowNullEndian1() { buffer(null, 0); } @Test(expected = NullPointerException.class) public void shouldDisallowNullEndian2() { directBuffer(null, 0); } @Test(expected = NullPointerException.class) public void shouldDisallowNullEndian3() { wrappedBuffer(null, new byte[0]); } @Test(expected = NullPointerException.class) public void shouldDisallowNullEndian4() { wrappedBuffer(null, new byte[0], 0, 0); } @Test public void shouldAllowEmptyBufferToCreateCompositeBuffer() { ChannelBuffer buf = wrappedBuffer( EMPTY_BUFFER, wrappedBuffer(LITTLE_ENDIAN, new byte[16]), EMPTY_BUFFER); assertEquals(16, buf.capacity()); } @Test public void testWrappedBuffer() { assertEquals(16, wrappedBuffer(ByteBuffer.allocateDirect(16)).capacity()); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), wrappedBuffer(new byte[][] { new byte[] { 1, 2, 3 } })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), wrappedBuffer( new byte[] { 1 }, new byte[] { 2 }, new byte[] { 3 })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), wrappedBuffer(new ChannelBuffer[] { wrappedBuffer(new byte[] { 1, 2, 3 }) })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), wrappedBuffer( wrappedBuffer(new byte[] { 1 }), wrappedBuffer(new byte[] { 2 }), wrappedBuffer(new byte[] { 3 }))); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), wrappedBuffer(new ByteBuffer[] { ByteBuffer.wrap(new byte[] { 1, 2, 3 }) })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), wrappedBuffer( ByteBuffer.wrap(new byte[] { 1 }), ByteBuffer.wrap(new byte[] { 2 }), ByteBuffer.wrap(new byte[] { 3 }))); } @Test public void testCopiedBuffer() { assertEquals(16, copiedBuffer(ByteBuffer.allocateDirect(16)).capacity()); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), copiedBuffer(new byte[][] { new byte[] { 1, 2, 3 } })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), copiedBuffer( new byte[] { 1 }, new byte[] { 2 }, new byte[] { 3 })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), copiedBuffer(new ChannelBuffer[] { wrappedBuffer(new byte[] { 1, 2, 3 }) })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), copiedBuffer( wrappedBuffer(new byte[] { 1 }), wrappedBuffer(new byte[] { 2 }), wrappedBuffer(new byte[] { 3 }))); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), copiedBuffer(new ByteBuffer[] { ByteBuffer.wrap(new byte[] { 1, 2, 3 }) })); assertEquals( wrappedBuffer(new byte[] { 1, 2, 3 }), copiedBuffer( ByteBuffer.wrap(new byte[] { 1 }), ByteBuffer.wrap(new byte[] { 2 }), ByteBuffer.wrap(new byte[] { 3 }))); } @Test public void testHexDump() { assertEquals("", hexDump(EMPTY_BUFFER)); assertEquals("123456", hexDump(wrappedBuffer( new byte[] { 0x12, 0x34, 0x56 }))); assertEquals("1234567890abcdef", hexDump(wrappedBuffer( new byte[] { 0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }))); } @Test public void testSwapMedium() { assertEquals(0x563412, swapMedium(0x123456)); assertEquals(0x80, swapMedium(0x800000)); } @Test public void testUnmodifiableBuffer() throws Exception { ChannelBuffer buf = unmodifiableBuffer(buffer(16)); try { buf.discardReadBytes(); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setByte(0, (byte) 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setBytes(0, EMPTY_BUFFER, 0, 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setBytes(0, new byte[0], 0, 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setBytes(0, ByteBuffer.allocate(0)); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setShort(0, (short) 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setMedium(0, 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setInt(0, 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setLong(0, 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setBytes(0, EasyMock.createMock(InputStream.class), 0); fail(); } catch (UnsupportedOperationException e) { // Expected } try { buf.setBytes(0, EasyMock.createMock(ScatteringByteChannel.class), 0); fail(); } catch (UnsupportedOperationException e) { // Expected } } /** * Test for https://github.com/netty/netty/issues/449 */ @Test public void testHexDumpOperations() { ChannelBuffer buffer = copiedBuffer("This is some testdata", CharsetUtil.ISO_8859_1); String hexDump = hexDump(buffer); ChannelBuffer buffer2 = hexDump(hexDump); assertEquals(buffer, buffer2); String hexDump2 = hexDump(buffer2); assertEquals(hexDump, hexDump2); } @Test public void testEmptyBuffer() { assertTrue(EMPTY_BUFFER instanceof EmptyChannelBuffer); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/DuplicateChannelBufferTest.java000066400000000000000000000025301225554127700321430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import org.junit.Test; /** * Tests duplicated channel buffers */ public class DuplicateChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = new DuplicatedChannelBuffer(ChannelBuffers.buffer(length)); assertEquals(0, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new DuplicatedChannelBuffer(null); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/DynamicChannelBufferTest.java000066400000000000000000000036641225554127700316260ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import java.nio.ByteOrder; import org.junit.Test; /** * Tests dynamic channel buffers */ public class DynamicChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.dynamicBuffer(length); assertEquals(0, buffer.readerIndex()); assertEquals(0, buffer.writerIndex()); assertEquals(length, buffer.capacity()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new DynamicChannelBuffer(null, 0); } @Test public void shouldNotFailOnInitialIndexUpdate() { new DynamicChannelBuffer(ByteOrder.BIG_ENDIAN, 10).setIndex(0, 10); } @Test public void shouldNotFailOnInitialIndexUpdate2() { new DynamicChannelBuffer(ByteOrder.BIG_ENDIAN, 10).writerIndex(10); } @Test public void shouldNotFailOnInitialIndexUpdate3() { ChannelBuffer buf = new DynamicChannelBuffer(ByteOrder.BIG_ENDIAN, 10); buf.writerIndex(10); buf.readerIndex(10); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/EmptyChannelBufferTest.java000066400000000000000000000704751225554127700313440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import org.jboss.netty.util.CharsetUtil; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.experimental.theories.suppliers.TestedOn; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import static java.nio.ByteOrder.BIG_ENDIAN; import static java.util.Arrays.asList; import static org.hamcrest.core.IsNot.not; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; import static org.junit.Assume.assumeThat; @RunWith(Theories.class) public class EmptyChannelBufferTest { @After public void assertInvariants() { assertEquals(0, b.readerIndex()); assertEquals(0, b.writerIndex()); assertEquals(0, b.writableBytes()); assertEquals(0, b.readableBytes()); assertFalse(b.writable()); assertFalse(b.readable()); } @Rule public ExpectedException thrown = ExpectedException.none(); public static final ScatteringByteChannel SINGLE_BYTE_CHANNEL = new ScatteringByteChannel() { public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { dsts[0].put((byte) 0); return 1; } public long read(ByteBuffer[] dsts) throws IOException { dsts[0].put((byte) 0); return 1; } public int read(ByteBuffer dst) throws IOException { dst.put((byte) 0); return 1; } public boolean isOpen() { return true; } public void close() throws IOException { } }; private static final ScatteringByteChannel EMPTY_BYTE_CHANNEL = new ScatteringByteChannel() { public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { return 0; } public long read(ByteBuffer[] dsts) throws IOException { return 0; } public int read(ByteBuffer dst) throws IOException { return 0; } public boolean isOpen() { return true; } public void close() throws IOException { } }; private static final GatheringByteChannel BYTE_CHANNEL_SINK = new GatheringByteChannel() { public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { int n = 0; for (ByteBuffer src : srcs) { n += write(src); } return n; } public long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, 0); } public int write(ByteBuffer src) throws IOException { int n = src.remaining(); src.get(new byte[src.remaining()]); return n; } public boolean isOpen() { return true; } public void close() throws IOException { } }; public static final byte[] SINGLE_BYTE = new byte[]{0}; public static final ChannelBufferIndexFinder POSITIVE_INDEX_FINDER = new ChannelBufferIndexFinder() { public boolean find(ChannelBuffer buffer, int guessedIndex) { return true; } }; public static final ChannelBuffer UNWRITTEN_BUFFER = buffer(1); final ChannelBuffer b = EMPTY_BUFFER; @Test public void testDiscardReadBytes() { b.discardReadBytes(); } @Test public void testClear() { b.clear(); } @Test public void testWriteBytes() throws IOException { b.writeBytes(new byte[]{}); b.writeBytes(new byte[]{}, 0, 0); b.writeBytes(ByteBuffer.wrap(new byte[]{})); b.writeBytes(buffer(0)); b.writeBytes(buffer(0), 0); b.writeBytes(buffer(0), 0, 0); b.writeBytes(new ChannelBufferInputStream(buffer(0)), 0); b.writeBytes(EMPTY_BYTE_CHANNEL, 0); } @Theory public void testWriteBytesIndexOutOfBounds1() throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(SINGLE_BYTE); } @Theory public void testWriteBytesIndexOutOfBounds3() throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(ByteBuffer.wrap(SINGLE_BYTE)); } @Theory public void testWriteBytesIndexOutOfBounds4() throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(wrappedBuffer(SINGLE_BYTE)); } @Theory public void testWriteBytesIndexOutOfBounds2(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(SINGLE_BYTE, 0, length); } @Theory public void testWriteBytesIndexOutOfBounds5(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(wrappedBuffer(SINGLE_BYTE), length); } @Theory public void testWriteBytesIndexOutOfBounds6(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(wrappedBuffer(SINGLE_BYTE), 0, length); } @Theory public void testWriteBytesIndexOutOfBounds7(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(new ChannelBufferInputStream(wrappedBuffer(SINGLE_BYTE)), length); } @Theory public void testWriteBytesIndexOutOfBounds8(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(SINGLE_BYTE_CHANNEL, length); } @Theory public void testWriteBytesIndexOutOfBounds9(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.writeBytes(SINGLE_BYTE, 0, length); } @Test public void testWriteZero() { b.writeZero(0); } @Theory public void testWriteZeroOutOfBounds(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.writeZero(length); } @Theory public void testSetZero(@TestedOn(ints = {-1, 1}) int offset) { b.setZero(0, 0); b.setZero(1, 0); b.setZero(-1, 0); } @Theory public void testSetZeroIllegalArgument() { thrown.expect(IllegalArgumentException.class); b.setZero(-1, -1); } @Theory public void testSetZeroOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.setZero(offset, 1); } @Test public void testSetBytes() { b.setBytes(0, wrappedBuffer(new byte[]{}), 0); b.setBytes(0, wrappedBuffer(new byte[]{}), 0, 0); b.setBytes(0, ByteBuffer.wrap(new byte[]{})); b.setBytes(0, buffer(0)); b.setBytes(0, buffer(0)); b.setBytes(0, buffer(0), 0); b.setBytes(0, buffer(0), 0, 0); } @Theory public void testSetBytesIndexOutOfBounds1(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.setBytes(offset, SINGLE_BYTE); } @Theory public void testSetBytesIndexOutOfBounds5(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.setBytes(offset, ByteBuffer.wrap(SINGLE_BYTE)); } @Theory public void testSetBytesIndexOutOfBounds2(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.setBytes(offset, SINGLE_BYTE, 0, length); } @Theory public void testSetBytesIndexOutOfBounds3(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.setBytes(offset, wrappedBuffer(SINGLE_BYTE), length); } @Theory public void testSetBytesIndexOutOfBounds4(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.setBytes(offset, wrappedBuffer(SINGLE_BYTE), 0, length); } @Theory public void testSetByteOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setByte(offset, value); } @Theory public void testSetCharOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setChar(offset, value); } @Theory public void testSetShortOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setShort(offset, value); } @Theory public void testSetMediumOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setMedium(offset, value); } @Theory public void testSetIntOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setInt(offset, value); } @Theory public void testSetLongOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setLong(offset, value); } @Theory public void testSetFloatOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setFloat(offset, value); } @Theory public void testSetDoubleOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.setDouble(offset, value); } @Theory public void testGetByteOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getByte(offset); } @Theory public void testGetCharOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getChar(offset); } @Theory public void testGetShortOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getShort(offset); } @Theory public void testGetMediumOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getMedium(offset); } @Theory public void testGetIntOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getInt(offset); } @Theory public void testGetLongOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getLong(offset); } @Theory public void testGetUnsignedByteOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getUnsignedByte(offset); } @Theory public void testGetUnsignedShortOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getUnsignedShort(offset); } @Theory public void testGetUnsignedMediumOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getUnsignedMedium(offset); } @Theory public void testGetUnsignedIntOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getUnsignedInt(offset); } @Theory public void testGetDoubleOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getDouble(offset); } @Theory public void testGetFloatOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getFloat(offset); } @Test public void testCopy() { assertEquals(EMPTY_BUFFER, b.copy()); assertEquals(EMPTY_BUFFER, b.copy(0, 0)); } @Theory public void testCopyOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.copy(offset, length); } @Test public void testReadByteOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readByte(); } @Test public void testReadCharOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readChar(); } @Test public void testReadDoubleOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readDouble(); } @Test public void testReadFloatOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readFloat(); } @Test public void testReadIntOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readInt(); } @Test public void testReadLongOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readLong(); } @Test public void testReadMediumOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readMedium(); } @Test public void testReadShortOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readShort(); } @Test public void testReadUnsignedByteOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readUnsignedByte(); } @Test public void testReadUnsignedIntOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readUnsignedInt(); } @Test public void testReadUnsignedMediumOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readUnsignedMedium(); } @Test public void testReadUnsignedShortOutOfBounds() { thrown.expect(IndexOutOfBoundsException.class); b.readUnsignedShort(); } @Theory public void testWriteByteOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeByte(value); } @Theory public void testWriteCharOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeChar(value); } @Theory public void testWriteDoubleOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeDouble(value); } @Theory public void testWriteFloatOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeFloat(value); } @Theory public void testWriteIntOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeInt(value); } @Theory public void testWriteLongOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeLong(value); } @Theory public void testWriteMediumOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeMedium(value); } @Theory public void testWriteShortOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int value) { thrown.expect(IndexOutOfBoundsException.class); b.writeShort(value); } @Test public void testReadBytes() throws IOException { assertEquals(EMPTY_BUFFER, b.readBytes(0)); b.readBytes(new byte[]{}); b.readBytes(new byte[]{}, 0, 0); b.readBytes(ByteBuffer.allocate(0)); b.readBytes(buffer(0)); b.readBytes(buffer(0), 0); b.readBytes(buffer(0), 0, 0); b.readBytes(BYTE_CHANNEL_SINK, 0); } @Theory public void testReadBytesOutOfBounds1(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(length); } @Theory public void testReadBytesOutOfBounds2() { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(new byte[1]); } @Theory public void testReadBytesOutOfBounds4() { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(ByteBuffer.allocate(1)); } @Theory public void testReadBytesOutOfBounds5() { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(buffer(1)); } @Theory public void testReadBytesOutOfBounds3(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(new byte[1], 0, length); } @Theory public void testReadBytesOutOfBounds6(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(buffer(1), length); } @Theory public void testReadBytesOutOfBounds7(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(buffer(1), 0, length); } @Theory public void testReadBytesOutOfBounds8(@TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.readBytes(BYTE_CHANNEL_SINK, length); } @Test public void testIndexes() { assertEquals(0, b.readerIndex()); assertEquals(0, b.writerIndex()); assertEquals(0, b.readableBytes()); assertEquals(0, b.writableBytes()); assertFalse(b.readable()); assertFalse(b.writable()); b.markReaderIndex(); b.markWriterIndex(); b.resetReaderIndex(); b.resetWriterIndex(); b.writerIndex(0); b.readerIndex(0); b.setIndex(0, 0); } @Theory public void testWriterIndexOutOfBounds(@TestedOn(ints = {-1, 1}) int index) { thrown.expect(IndexOutOfBoundsException.class); b.writerIndex(index); } @Theory public void testReaderIndexOutOfBounds(@TestedOn(ints = {-1, 1}) int index) { thrown.expect(IndexOutOfBoundsException.class); b.readerIndex(index); } @Theory public void testIndexesOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int writer, @TestedOn(ints = {-1, 0, 1}) int reader) { assumeThat(asList(writer, reader), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.setIndex(reader, writer); } @Theory public void testIndexOf(@TestedOn(ints = {-1, 0, 1}) int from, @TestedOn(ints = {-1, 0, 1}) int to, @TestedOn(ints = {-1, 0, 1}) int value) { assertEquals(-1, b.indexOf(from, to, (byte) value)); } @Test public void testEquals() { assertTrue(b.equals(EMPTY_BUFFER)); assertTrue(b.equals(ChannelBuffers.buffer(1))); assertFalse(b.equals(wrappedBuffer(SINGLE_BYTE))); } @Test public void testFactory() { assertEquals(HeapChannelBufferFactory.getInstance(BIG_ENDIAN), b.factory()); } @Test public void testEnsureWritableBytes() { b.ensureWritableBytes(0); try { b.ensureWritableBytes(1); fail(); } catch (IndexOutOfBoundsException e) { // Expected } } @Test public void testSlice() { assertEquals(EMPTY_BUFFER, b.slice()); assertEquals(EMPTY_BUFFER, b.slice(0, 0)); } @Theory public void testSliceOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.slice(offset, length); } @Test public void testReadSlice() { assertEquals(EMPTY_BUFFER, b.readSlice(0)); } @Theory public void testReadSliceOutOfBounds(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.readSlice(length); } @Test public void testDuplicate() { assertEquals(EMPTY_BUFFER, b.duplicate()); } @Theory public void testBytesBefore(@TestedOn(ints = {-1, 0, 1}) int value) { assertEquals(-1, b.bytesBefore((byte) value)); assertEquals(-1, b.bytesBefore(POSITIVE_INDEX_FINDER)); assertEquals(-1, b.bytesBefore(0, (byte) value)); assertEquals(-1, b.bytesBefore(0, (byte) value)); assertEquals(-1, b.bytesBefore(0, 0, (byte) value)); assertEquals(-1, b.bytesBefore(0, 0, POSITIVE_INDEX_FINDER)); } @Theory public void testBytesBeforeOutOfBounds1(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.bytesBefore(length, POSITIVE_INDEX_FINDER); } @Theory public void testBytesBeforeOutOfBounds2(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.bytesBefore(offset, length, POSITIVE_INDEX_FINDER); b.bytesBefore(offset, length, POSITIVE_INDEX_FINDER); } @Test public void testOrder() { assertEquals(ChannelBuffers.BIG_ENDIAN, b.order()); } @Test public void testArray() { assertEquals(0, b.array().length); assertEquals(0, b.arrayOffset()); assertTrue(b.hasArray()); } @Test public void testCapacity() { assertEquals(0, b.capacity()); } @Test public void testCompareTo() { assertEquals(-1, b.compareTo(wrappedBuffer(SINGLE_BYTE))); assertEquals(0, b.compareTo(buffer(0))); assertEquals(0, b.compareTo(new BigEndianHeapChannelBuffer(0))); assertEquals(0, b.compareTo(new BigEndianHeapChannelBuffer(1))); } @Test public void testIsDirect() { assertFalse(b.isDirect()); } @Test public void testToByteBuffer() { assertEquals(ByteBuffer.allocate(0), b.toByteBuffer()); assertEquals(ByteBuffer.allocate(0), b.toByteBuffer(0, 0)); } @Theory public void testToByteBufferOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.toByteBuffer(offset, length); } @Test public void testToByteBuffers() { assertArrayEquals(new ByteBuffer[]{ByteBuffer.allocate(0)}, b.toByteBuffers()); assertArrayEquals(new ByteBuffer[]{ByteBuffer.allocate(0)}, b.toByteBuffers(0, 0)); } @Theory public void testToByteBuffersOutOfBounds(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.toByteBuffers(offset, length); } @Test public void testGetBytes() throws IOException { b.getBytes(0, new byte[0]); b.getBytes(0, new byte[0], 0, 0); b.getBytes(0, ByteBuffer.allocate(0)); b.getBytes(0, buffer(0)); b.getBytes(0, buffer(0), 0); b.getBytes(0, buffer(0), 0, 0); b.getBytes(0, BYTE_CHANNEL_SINK, 0); b.getBytes(0, new ChannelBufferOutputStream(buffer(0)), 0); } @Theory public void testGetBytesOutOfBounds1(@TestedOn(ints = {-1, 0, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, new byte[1]); } @Theory public void testGetBytesOutOfBounds2(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, new byte[1], 0, length); } @Theory public void testGetBytesOutOfBounds3(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, buffer(1)); } @Theory public void testGetBytesOutOfBounds4(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, buffer(1), length); } @Theory public void testGetBytesOutOfBounds5(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, buffer(1), 0, length); } @Theory public void testGetBytesOutOfBounds7(@TestedOn(ints = {-1, 1}) int offset) { thrown.expect(IndexOutOfBoundsException.class); thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, ByteBuffer.allocate(1)); } @Theory public void testGetBytesOutOfBounds6(@TestedOn(ints = {-1, 0, 1}) int offset, @TestedOn(ints = {-1, 0, 1}) int length) throws IOException { assumeThat(asList(offset, length), not(asList(0, 0))); thrown.expect(IndexOutOfBoundsException.class); b.getBytes(offset, BYTE_CHANNEL_SINK, length); } @Theory public void testGetBytesOutOfBounds8(@TestedOn(ints = {-1, 0, 1}) int index, @TestedOn(ints = {-1, 1}) int length) throws IOException { thrown.expect(IndexOutOfBoundsException.class); b.getBytes(index, new ChannelBufferOutputStream(buffer(1)), length); } @Test public void testSkipBytes() { b.skipBytes(0); } @Theory public void testSkipBytesOutOfBounds(@TestedOn(ints = {-1, 1}) int length) { thrown.expect(IndexOutOfBoundsException.class); b.skipBytes(length); } @Test public void testHashCode() { assertEquals(ChannelBuffers.hashCode(UNWRITTEN_BUFFER), b.hashCode()); } @Test public void testToString() { b.toString(); assertEquals("", b.toString(CharsetUtil.UTF_8)); assertEquals("", b.toString(0, 0, CharsetUtil.UTF_8)); } } LittleEndianCompositeChannelBufferTest.java000066400000000000000000000016421225554127700344140ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; /** * Tests little-endian composite channel buffers */ public class LittleEndianCompositeChannelBufferTest extends AbstractCompositeChannelBufferTest { public LittleEndianCompositeChannelBufferTest() { super(ChannelBuffers.LITTLE_ENDIAN); } } LittleEndianDirectChannelBufferTest.java000066400000000000000000000024271225554127700336660ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import java.nio.ByteOrder; /** * Tests little-endian direct channel buffers */ public class LittleEndianDirectChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.directBuffer(ByteOrder.LITTLE_ENDIAN, length); assertSame(ByteOrder.LITTLE_ENDIAN, buffer.order()); assertEquals(0, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/LittleEndianHeapChannelBufferTest.java000066400000000000000000000026051225554127700334060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import java.nio.ByteOrder; import org.junit.Test; /** * Tests little-endian heap channel buffers */ public class LittleEndianHeapChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.buffer(ByteOrder.LITTLE_ENDIAN, length); assertEquals(0, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new LittleEndianHeapChannelBuffer(null); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/ReadOnlyChannelBufferTest.java000066400000000000000000000147441225554127700317600ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.easymock.EasyMock.*; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import org.junit.Test; /** * Tests read-only channel buffers */ public class ReadOnlyChannelBufferTest { @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new ReadOnlyChannelBuffer(null); } @Test public void testUnmodifiableBuffer() { assertTrue(unmodifiableBuffer(buffer(1)) instanceof ReadOnlyChannelBuffer); } @Test public void testUnwrap() { ChannelBuffer buf = buffer(1); assertSame(buf, ((WrappedChannelBuffer) ChannelBuffers.unmodifiableBuffer(buf)).unwrap()); } @Test public void shouldHaveSameByteOrder() { ChannelBuffer buf = buffer(LITTLE_ENDIAN, 1); assertSame(LITTLE_ENDIAN, ChannelBuffers.unmodifiableBuffer(buf).order()); } @Test public void shouldReturnReadOnlyDerivedBuffer() { ChannelBuffer buf = unmodifiableBuffer(buffer(1)); assertTrue(buf.duplicate() instanceof ReadOnlyChannelBuffer); assertTrue(buf.slice() instanceof ReadOnlyChannelBuffer); assertTrue(buf.slice(0, 1) instanceof ReadOnlyChannelBuffer); assertTrue(buf.duplicate() instanceof ReadOnlyChannelBuffer); } @Test public void shouldReturnWritableCopy() { ChannelBuffer buf = unmodifiableBuffer(buffer(1)); assertFalse(buf.copy() instanceof ReadOnlyChannelBuffer); } @Test public void shouldForwardReadCallsBlindly() throws Exception { ChannelBuffer buf = createStrictMock(ChannelBuffer.class); expect(buf.readerIndex()).andReturn(0).anyTimes(); expect(buf.writerIndex()).andReturn(0).anyTimes(); expect(buf.capacity()).andReturn(0).anyTimes(); expect(buf.getBytes(1, (GatheringByteChannel) null, 2)).andReturn(3); buf.getBytes(4, (OutputStream) null, 5); buf.getBytes(6, (byte[]) null, 7, 8); buf.getBytes(9, (ChannelBuffer) null, 10, 11); buf.getBytes(12, (ByteBuffer) null); expect(buf.getByte(13)).andReturn(Byte.valueOf((byte) 14)); expect(buf.getShort(15)).andReturn(Short.valueOf((short) 16)); expect(buf.getUnsignedMedium(17)).andReturn(18); expect(buf.getInt(19)).andReturn(20); expect(buf.getLong(21)).andReturn(22L); ByteBuffer bb = ByteBuffer.allocate(100); ByteBuffer[] bbs = { ByteBuffer.allocate(101), ByteBuffer.allocate(102) }; expect(buf.toByteBuffer(23, 24)).andReturn(bb); expect(buf.toByteBuffers(25, 26)).andReturn(bbs); expect(buf.capacity()).andReturn(27); replay(buf); ChannelBuffer roBuf = unmodifiableBuffer(buf); assertEquals(3, roBuf.getBytes(1, (GatheringByteChannel) null, 2)); roBuf.getBytes(4, (OutputStream) null, 5); roBuf.getBytes(6, (byte[]) null, 7, 8); roBuf.getBytes(9, (ChannelBuffer) null, 10, 11); roBuf.getBytes(12, (ByteBuffer) null); assertEquals((byte) 14, roBuf.getByte(13)); assertEquals((short) 16, roBuf.getShort(15)); assertEquals(18, roBuf.getUnsignedMedium(17)); assertEquals(20, roBuf.getInt(19)); assertEquals(22L, roBuf.getLong(21)); ByteBuffer roBB = roBuf.toByteBuffer(23, 24); assertEquals(100, roBB.capacity()); assertTrue(roBB.isReadOnly()); ByteBuffer[] roBBs = roBuf.toByteBuffers(25, 26); assertEquals(2, roBBs.length); assertEquals(101, roBBs[0].capacity()); assertTrue(roBBs[0].isReadOnly()); assertEquals(102, roBBs[1].capacity()); assertTrue(roBBs[1].isReadOnly()); assertEquals(27, roBuf.capacity()); verify(buf); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectDiscardReadBytes() { unmodifiableBuffer(EMPTY_BUFFER).discardReadBytes(); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetByte() { unmodifiableBuffer(EMPTY_BUFFER).setByte(0, (byte) 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetShort() { unmodifiableBuffer(EMPTY_BUFFER).setShort(0, (short) 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetMedium() { unmodifiableBuffer(EMPTY_BUFFER).setMedium(0, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetInt() { unmodifiableBuffer(EMPTY_BUFFER).setInt(0, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetLong() { unmodifiableBuffer(EMPTY_BUFFER).setLong(0, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetBytes1() throws IOException { unmodifiableBuffer(EMPTY_BUFFER).setBytes(0, (InputStream) null, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetBytes2() throws IOException { unmodifiableBuffer(EMPTY_BUFFER).setBytes(0, (ScatteringByteChannel) null, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetBytes3() { unmodifiableBuffer(EMPTY_BUFFER).setBytes(0, (byte[]) null, 0, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetBytes4() { unmodifiableBuffer(EMPTY_BUFFER).setBytes(0, (ChannelBuffer) null, 0, 0); } @Test(expected = UnsupportedOperationException.class) public void shouldRejectSetBytes5() { unmodifiableBuffer(EMPTY_BUFFER).setBytes(0, (ByteBuffer) null); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/SlicedChannelBufferTest.java000066400000000000000000000027231225554127700314400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import java.util.Random; import org.junit.Test; /** * Tests sliced channel buffers */ public class SlicedChannelBufferTest extends AbstractChannelBufferTest { private final Random random = new Random(); private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.wrappedBuffer( new byte[length * 2], random.nextInt(length - 1) + 1, length); assertEquals(length, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new SlicedChannelBuffer(null, 0, 0); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/buffer/TruncatedChannelBufferTest.java000066400000000000000000000025621225554127700321670ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.buffer; import static org.junit.Assert.*; import org.junit.Test; /** * Tests truncated channel buffers */ public class TruncatedChannelBufferTest extends AbstractChannelBufferTest { private ChannelBuffer buffer; @Override protected ChannelBuffer newBuffer(int length) { buffer = ChannelBuffers.wrappedBuffer( new byte[length * 2], 0, length); assertEquals(length, buffer.writerIndex()); return buffer; } @Override protected ChannelBuffer[] components() { return new ChannelBuffer[] { buffer }; } @Test(expected = NullPointerException.class) public void shouldNotAllowNullInConstructor() { new TruncatedChannelBuffer(null, 0); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/000077500000000000000000000000001225554127700242425ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/CompleteChannelFutureTest.java000066400000000000000000000066541225554127700322140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.junit.Before; import org.junit.Test; import java.util.concurrent.TimeUnit; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; public class CompleteChannelFutureTest { private final Channel channel = createMock(Channel.class); private CompleteChannelFuture future; @Before public void init() { future = new CompleteChannelFutureImpl(channel); } @Test(expected = NullPointerException.class) public void shouldDisallowNullChannel() { new CompleteChannelFutureImpl(null); } @Test public void shouldNotifyImmediatelyOnAdd() throws Exception { ChannelFutureListener l = createStrictMock(ChannelFutureListener.class); l.operationComplete(future); replay(l); future.addListener(l); verify(l); } @Test public void shouldNotRethrowListenerException() { ChannelFutureListener l = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { throw new ExpectedError(); } }; future.addListener(l); } @Test public void shouldNotDoAnythingOnRemove() throws Exception { ChannelFutureListener l = createStrictMock(ChannelFutureListener.class); replay(l); future.removeListener(l); verify(l); } @Test public void testConstantProperties() throws InterruptedException { assertSame(channel, future.getChannel()); assertTrue(future.isDone()); assertFalse(future.cancel()); assertFalse(future.isCancelled()); assertSame(future, future.await()); assertTrue(future.await(1)); assertTrue(future.await(1, TimeUnit.NANOSECONDS)); assertSame(future, future.awaitUninterruptibly()); assertTrue(future.awaitUninterruptibly(1)); assertTrue(future.awaitUninterruptibly(1, TimeUnit.NANOSECONDS)); } private static class CompleteChannelFutureImpl extends CompleteChannelFuture { CompleteChannelFutureImpl(Channel channel) { super(channel); } public Throwable getCause() { throw new Error(); } public boolean isSuccess() { throw new Error(); } @Deprecated public ChannelFuture rethrowIfFailed() throws Exception { throw new Error(); } public ChannelFuture sync() throws InterruptedException { throw new Error(); } public ChannelFuture syncUninterruptibly() { throw new Error(); } } private static class ExpectedError extends Error { private static final long serialVersionUID = 7059276744882005047L; ExpectedError() { } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/DefaultChannelPipelineTest.java000066400000000000000000000112461225554127700323140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.junit.Test; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.junit.Assert.*; public class DefaultChannelPipelineTest { @Test public void testReplaceChannelHandler() { DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); SimpleChannelHandler handler1 = new SimpleChannelHandler(); pipeline.addLast("handler1", handler1); pipeline.addLast("handler2", handler1); pipeline.addLast("handler3", handler1); assertSame(pipeline.get("handler1"), handler1); assertSame(pipeline.get("handler2"), handler1); assertSame(pipeline.get("handler3"), handler1); SimpleChannelHandler newHandler1 = new SimpleChannelHandler(); pipeline.replace("handler1", "handler1", newHandler1); assertSame(pipeline.get("handler1"), newHandler1); SimpleChannelHandler newHandler3 = new SimpleChannelHandler(); pipeline.replace("handler3", "handler3", newHandler3); assertSame(pipeline.get("handler3"), newHandler3); SimpleChannelHandler newHandler2 = new SimpleChannelHandler(); pipeline.replace("handler2", "handler2", newHandler2); assertSame(pipeline.get("handler2"), newHandler2); } // Test for #505 @Test public void testToString() { DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); assertNotNull(pipeline.toString()); } @Test public void testLifeCycleAware() { DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); List handlers = new ArrayList(); for (int i = 0; i < 20; i++) { LifeCycleAwareTestHandler handler = new LifeCycleAwareTestHandler("handler-" + i); // Add handler. pipeline.addFirst(handler.name, handler); // Validate handler life-cycle methods called. handler.validate(true, true, false, false); // Store handler into the list. handlers.add(handler); } // Change the order of remove operations over all handlers in the pipeline. Collections.shuffle(handlers); for (LifeCycleAwareTestHandler handler : handlers) { assertSame(handler, pipeline.remove(handler.name)); // Validate handler life-cycle methods called. handler.validate(true, true, true, true); } } /** Test handler to validate life-cycle aware behavior. */ private static final class LifeCycleAwareTestHandler extends SimpleChannelHandler implements LifeCycleAwareChannelHandler { private final String name; private boolean beforeAdd; private boolean afterAdd; private boolean beforeRemove; private boolean afterRemove; /** * Constructs life-cycle aware test handler. * * @param name Handler name to display in assertion messages. */ private LifeCycleAwareTestHandler(String name) { this.name = name; } public void validate(boolean beforeAdd, boolean afterAdd, boolean beforeRemove, boolean afterRemove) { assertEquals(name, beforeAdd, this.beforeAdd); assertEquals(name, afterAdd, this.afterAdd); assertEquals(name, beforeRemove, this.beforeRemove); assertEquals(name, afterRemove, this.afterRemove); } public void beforeAdd(ChannelHandlerContext ctx) { validate(false, false, false, false); beforeAdd = true; } public void afterAdd(ChannelHandlerContext ctx) { validate(true, false, false, false); afterAdd = true; } public void beforeRemove(ChannelHandlerContext ctx) { validate(true, true, false, false); beforeRemove = true; } public void afterRemove(ChannelHandlerContext ctx) { validate(true, true, true, false); afterRemove = true; } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/FailedChannelFutureTest.java000066400000000000000000000024071225554127700316200ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.junit.Test; public class FailedChannelFutureTest { @Test public void testConstantProperties() { Channel channel = createMock(Channel.class); Exception e = new Exception(); FailedChannelFuture future = new FailedChannelFuture(channel, e); assertFalse(future.isSuccess()); assertSame(e, future.getCause()); } @Test(expected = NullPointerException.class) public void shouldDisallowNullException() { new FailedChannelFuture(createMock(Channel.class), null); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/StaticChannelPipelineTest.java000066400000000000000000000042261225554127700321570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import org.junit.Assert; import org.junit.Test; import java.util.Map; @SuppressWarnings("deprecation") public class StaticChannelPipelineTest { @Test public void testConstructionWithoutNull() { StaticChannelPipeline p = new StaticChannelPipeline(new A(), new B()); Map m = p.toMap(); Assert.assertEquals(2, m.size()); Assert.assertTrue(m.get("0") instanceof A); Assert.assertTrue(m.get("1") instanceof B); } @Test public void testConstructionWithNull1() { StaticChannelPipeline p = new StaticChannelPipeline(null, new A(), new B()); Map m = p.toMap(); Assert.assertEquals(0, m.size()); } @Test public void testConstructionWithNull2() { StaticChannelPipeline p = new StaticChannelPipeline(new A(), null, new B()); Map m = p.toMap(); Assert.assertEquals(1, m.size()); Assert.assertTrue(m.get("0") instanceof A); } @Test public void testConstructionWithNull() { StaticChannelPipeline p = new StaticChannelPipeline(new A(), new B(), null); Map m = p.toMap(); Assert.assertEquals(2, m.size()); Assert.assertTrue(m.get("0") instanceof A); Assert.assertTrue(m.get("1") instanceof B); } static final class A extends SimpleChannelHandler { // Dummy } static final class B extends SimpleChannelHandler { // Dummy } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/SucceededChannelFutureTest.java000066400000000000000000000020701225554127700323140ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.junit.Test; public class SucceededChannelFutureTest { @Test public void testConstantProperties() { Channel channel = createMock(Channel.class); SucceededChannelFuture future = new SucceededChannelFuture(channel); assertTrue(future.isSuccess()); assertNull(future.getCause()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/local/000077500000000000000000000000001225554127700253345ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/local/LocalAddressTest.java000066400000000000000000000122061225554127700314000ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.junit.Test; import static org.junit.Assert.*; public class LocalAddressTest { private static final String LOCAL_ADDR_ID = "test.id"; @Test public void localConnectOK() throws Exception { ClientBootstrap cb = new ClientBootstrap(new DefaultLocalClientChannelFactory()); ServerBootstrap sb = new ServerBootstrap(new DefaultLocalServerChannelFactory()); cb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("test.handler", new TestHandler()); return pipeline; } }); sb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("test.handler", new TestHandler()); return pipeline; } }); LocalAddress addr = new LocalAddress(LOCAL_ADDR_ID); // Start server sb.bind(addr); // Connect to the server ChannelFuture connectFuture = cb.connect(addr); connectFuture.awaitUninterruptibly(); // Send a message event up the pipeline. Channels.fireMessageReceived(connectFuture.getChannel(), "Hello, World"); // Close the channel connectFuture.getChannel().close(); // Wait until the connection is closed, or the connection attempt fails connectFuture.getChannel().getCloseFuture().awaitUninterruptibly(); sb.releaseExternalResources(); cb.releaseExternalResources(); assertNull(String.format("Expected null, got channel '%s' for local address '%s'", LocalChannelRegistry.getChannel(addr), addr), LocalChannelRegistry.getChannel(addr)); } @Test public void localConnectAgain() throws Exception { ClientBootstrap cb = new ClientBootstrap(new DefaultLocalClientChannelFactory()); ServerBootstrap sb = new ServerBootstrap(new DefaultLocalServerChannelFactory()); cb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("test.handler", new TestHandler()); return pipeline; } }); sb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("test.handler", new TestHandler()); return pipeline; } }); LocalAddress addr = new LocalAddress(LOCAL_ADDR_ID); // Start server sb.bind(addr); // Connect to the server ChannelFuture connectFuture = cb.connect(addr); connectFuture.awaitUninterruptibly(); // Send a message event up the pipeline. Channels.fireMessageReceived(connectFuture.getChannel(), "Hello, World"); // Close the channel connectFuture.getChannel().close(); // Wait until the connection is closed, or the connection attempt fails connectFuture.getChannel().getCloseFuture().awaitUninterruptibly(); sb.releaseExternalResources(); cb.releaseExternalResources(); assertNull(String.format("Expected null, got channel '%s' for local address '%s'", LocalChannelRegistry.getChannel(addr), addr), LocalChannelRegistry.getChannel(addr)); } public static class TestHandler extends SimpleChannelUpstreamHandler { @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { System.err.println(String.format("Received upstream event '%s'", e)); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/local/LocalClientTest.java000066400000000000000000000056771225554127700312470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.local; import static org.junit.Assert.*; import java.util.concurrent.CountDownLatch; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.junit.Test; public class LocalClientTest { @Test public void testLocalAddressBind() throws InterruptedException { ServerBootstrap sb = new ServerBootstrap(new DefaultLocalServerChannelFactory()); LocalAddress addr = new LocalAddress("Server"); LocalAddress addr2 = new LocalAddress("C1"); sb.bind(addr); ClientBootstrap cb = new ClientBootstrap(new DefaultLocalClientChannelFactory()); final ExceptionHandler handler = new ExceptionHandler(); cb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(handler); } }); ChannelFuture cf = cb.connect(addr, addr2).awaitUninterruptibly(); assertTrue(cf.isSuccess()); assertTrue(cf.getChannel().close().awaitUninterruptibly().isSuccess()); assertNull(handler.await()); sb.releaseExternalResources(); cb.releaseExternalResources(); } static final class ExceptionHandler extends SimpleChannelUpstreamHandler { private final CountDownLatch latch = new CountDownLatch(1); private Throwable t; @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { super.exceptionCaught(ctx, e); t = e.getCause(); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelClosed(ctx, e); latch.countDown(); } public Throwable await() throws InterruptedException { latch.await(); return t; } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/000077500000000000000000000000001225554127700255325ustar00rootroot00000000000000AbstractDatagramMulticastTest.java000066400000000000000000000137341225554127700342600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import static org.junit.Assert.*; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; public abstract class AbstractDatagramMulticastTest { protected abstract DatagramChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract DatagramChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testMulticast() throws Throwable { ConnectionlessBootstrap sb = new ConnectionlessBootstrap( newServerSocketChannelFactory(Executors.newCachedThreadPool())); ConnectionlessBootstrap cb = new ConnectionlessBootstrap( newClientSocketChannelFactory(Executors.newCachedThreadPool())); DatagramChannel sc = null; DatagramChannel cc = null; try { MulticastTestHandler mhandler = new MulticastTestHandler(); cb.getPipeline().addFirst("handler", mhandler); sb.getPipeline().addFirst("handler", new SimpleChannelUpstreamHandler()); int port = TestUtil.getFreePort(); NetworkInterface loopbackIf; try { loopbackIf = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()); } catch (SocketException e) { loopbackIf = null; } // check if the NetworkInterface is null, this is the case on my ubuntu dev machine but not on osx and windows. // if so fail back the the first interface if (loopbackIf == null) { for (Enumeration e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements();) { NetworkInterface nif = e.nextElement(); if (nif.isLoopback()) { loopbackIf = nif; break; } } } sb.setOption("networkInterface", loopbackIf); sb.setOption("reuseAddress", true); sc = (DatagramChannel) sb.bind(new InetSocketAddress(port)); String group = "230.0.0.1"; InetSocketAddress groupAddress = new InetSocketAddress(group, port); cb.setOption("networkInterface", loopbackIf); cb.setOption("reuseAddress", true); cc = (DatagramChannel) cb.bind(new InetSocketAddress(port)); assertTrue(cc.joinGroup(groupAddress, loopbackIf).awaitUninterruptibly().isSuccess()); assertTrue(sc.write(wrapInt(1), groupAddress).awaitUninterruptibly().isSuccess()); assertTrue(mhandler.await()); assertTrue(sc.write(wrapInt(1), groupAddress).awaitUninterruptibly().isSuccess()); // leave the group assertTrue(cc.leaveGroup(groupAddress, loopbackIf).awaitUninterruptibly().isSuccess()); // sleep a second to make sure we left the group Thread.sleep(1000); // we should not receive a message anymore as we left the group before assertTrue(sc.write(wrapInt(1), groupAddress).awaitUninterruptibly().isSuccess()); } finally { if (sc != null) { sc.close().awaitUninterruptibly(); } if (cc != null) { cc.close().awaitUninterruptibly(); } sb.releaseExternalResources(); cb.releaseExternalResources(); } } private static ChannelBuffer wrapInt(int value) { ChannelBuffer buf = ChannelBuffers.buffer(4); buf.writeInt(value); return buf; } private static final class MulticastTestHandler extends SimpleChannelUpstreamHandler { private final CountDownLatch latch = new CountDownLatch(1); private boolean done; private volatile boolean fail; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { super.messageReceived(ctx, e); if (done) { fail = true; } assertEquals(1, ((ChannelBuffer) e.getMessage()).readInt()); latch.countDown(); // mark the handler as done as we only are supposed to receive one message done = true; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); } public boolean await() throws Exception { boolean success = latch.await(10, TimeUnit.SECONDS); if (fail) { // fail if we receive an message after we are done fail(); } return success; } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/AbstractDatagramTest.java000066400000000000000000000056121225554127700324450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.junit.Test; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; public abstract class AbstractDatagramTest { protected abstract DatagramChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract DatagramChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testSimpleSend() throws Throwable { ConnectionlessBootstrap sb = new ConnectionlessBootstrap( newServerSocketChannelFactory(Executors.newCachedThreadPool())); ConnectionlessBootstrap cb = new ConnectionlessBootstrap( newClientSocketChannelFactory(Executors.newCachedThreadPool())); final CountDownLatch latch = new CountDownLatch(1); sb.getPipeline().addFirst("handler", new SimpleChannelUpstreamHandler() { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { super.messageReceived(ctx, e); assertEquals(1, ((ChannelBuffer) e.getMessage()).readInt()); latch.countDown(); } }); cb.getPipeline().addFirst("handler", new SimpleChannelUpstreamHandler()); Channel sc = sb.bind(new InetSocketAddress("127.0.0.1",0)); Channel cc = cb.bind(new InetSocketAddress("127.0.0.1", 0)); ChannelBuffer buf = ChannelBuffers.dynamicBuffer(); buf.writeInt(1); cc.write(buf, sc.getLocalAddress()); assertTrue(latch.await(10, TimeUnit.SECONDS)); sc.close().awaitUninterruptibly(); cc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/AbstractSocketEchoTest.java000066400000000000000000000137451225554127700327620ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.jboss.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public abstract class AbstractSocketEchoTest { private static final Random random = new Random(); static final byte[] data = new byte[1048576]; private static ExecutorService executor; static { random.nextBytes(data); } @BeforeClass public static void init() { executor = Executors.newCachedThreadPool(); } @AfterClass public static void destroy() { ExecutorUtil.terminate(executor); } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testSimpleEcho() throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(executor)); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(executor)); EchoHandler sh = new EchoHandler(); EchoHandler ch = new EchoHandler(); sb.getPipeline().addFirst("handler", sh); cb.getPipeline().addFirst("handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); for (int i = 0; i < data.length;) { int length = Math.min(random.nextInt(1024 * 64), data.length - i); cc.write(ChannelBuffers.wrappedBuffer(data, i, length)); i += length; } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; EchoHandler() { } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer m = (ChannelBuffer) e.getMessage(); byte[] actual = new byte[m.readableBytes()]; m.getBytes(0, actual); int lastIdx = counter; for (int i = 0; i < actual.length; i ++) { assertEquals(data[i + lastIdx], actual[i]); } if (channel.getParent() != null) { channel.write(m); } counter += actual.length; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (exception.compareAndSet(null, e.getCause())) { e.getChannel().close(); } } } } NioClientSocketShutdownTimeTest.java000066400000000000000000000052411225554127700345700ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.util.DummyHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; public class NioClientSocketShutdownTimeTest { @Test public void testShutdownTime() throws Throwable { ServerSocketChannel serverSocket = ServerSocketChannel.open(); serverSocket.socket().bind(new InetSocketAddress(0)); ClientBootstrap b = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); b.getPipeline().addLast("handler", new DummyHandler()); long startTime; long stopTime; try { serverSocket.configureBlocking(false); ChannelFuture f = b.connect(new InetSocketAddress( TestUtil.getLocalHost(), serverSocket.socket().getLocalPort())); serverSocket.accept(); f.awaitUninterruptibly(); if (f.getCause() != null) { throw f.getCause(); } assertTrue(f.isSuccess()); startTime = System.currentTimeMillis(); f.getChannel().close().awaitUninterruptibly(); } finally { b.getFactory().releaseExternalResources(); stopTime = System.currentTimeMillis(); try { serverSocket.close(); } catch (IOException ex) { // Ignore. } } b.releaseExternalResources(); long shutdownTime = stopTime - startTime; assertTrue("Shutdown takes too long: " + shutdownTime + " ms", shutdownTime < 500); } } NioNioDatagramMulticastTest.java000066400000000000000000000024121225554127700336770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.junit.Ignore; @Ignore public class NioNioDatagramMulticastTest extends AbstractDatagramMulticastTest { @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor, InternetProtocolFamily.IPv4); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor, InternetProtocolFamily.IPv4); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/NioNioDatagramTest.java000066400000000000000000000022351225554127700320730ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; public class NioNioDatagramTest extends AbstractDatagramTest { @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor); } }netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/NioNioSocketEchoTest.java000066400000000000000000000024511225554127700324020ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketEchoTest extends AbstractSocketEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } NioOioDatagramMulticastTest.java000066400000000000000000000024621225554127700337050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; import org.junit.Ignore; @Ignore public class NioOioDatagramMulticastTest extends AbstractDatagramMulticastTest { @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor, InternetProtocolFamily.IPv4); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/NioOioDatagramTest.java000066400000000000000000000023421225554127700320730ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; public class NioOioDatagramTest extends AbstractDatagramTest{ @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor); } @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } }netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/NioOioSocketEchoTest.java000066400000000000000000000024511225554127700324030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketEchoTest extends AbstractSocketEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } NioServerSocketShutdownTimeTest.java000066400000000000000000000066301225554127700346230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.util.TestUtil; import org.junit.Test; public class NioServerSocketShutdownTimeTest { @Test(timeout = 10000) public void testSuccessfulBindAttempt() throws Exception { ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); bootstrap.setOption("localAddress", new InetSocketAddress(0)); bootstrap.setOption("child.receiveBufferSize", 9753); bootstrap.setOption("child.sendBufferSize", 8642); DummyHandler handler = new DummyHandler(); bootstrap.getPipeline().addLast("dummy", handler); Channel channel = bootstrap.bind(); final long startTime; Socket socket = null; try { socket = new Socket( TestUtil.getLocalHost(), ((InetSocketAddress) channel.getLocalAddress()).getPort()); while (!handler.connected) { Thread.yield(); } socket.close(); while (!handler.closed) { Thread.yield(); } } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { // Ignore. } } startTime = System.currentTimeMillis(); channel.close().awaitUninterruptibly(); bootstrap.getFactory().releaseExternalResources(); } long shutdownTime = System.currentTimeMillis() - startTime; assertTrue("Shutdown takes too long: " + shutdownTime + " ms", shutdownTime < 500); } private static class DummyHandler extends SimpleChannelUpstreamHandler { volatile boolean connected; volatile boolean closed; DummyHandler() { } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { connected = true; } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { closed = true; } } } OioNioDatagramMulticastTest.java000066400000000000000000000024621225554127700337050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; import org.junit.Ignore; @Ignore public class OioNioDatagramMulticastTest extends AbstractDatagramMulticastTest { @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor, InternetProtocolFamily.IPv4); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/OioNioDatagramTest.java000066400000000000000000000023401225554127700320710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; public class OioNioDatagramTest extends AbstractDatagramTest{ @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioDatagramChannelFactory(executor); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } }netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/OioNioSocketEchoTest.java000066400000000000000000000024371225554127700324070ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; public class OioNioSocketEchoTest extends AbstractSocketEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } OioOioDatagramMulticastTest.java000066400000000000000000000023201225554127700336770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; import org.junit.Ignore; @Ignore public class OioOioDatagramMulticastTest extends AbstractDatagramMulticastTest { @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/OioOioDatagramTest.java000066400000000000000000000022341225554127700320740ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; public class OioOioDatagramTest extends AbstractDatagramTest{ @Override protected DatagramChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } @Override protected DatagramChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioDatagramChannelFactory(executor); } }netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/OioOioSocketEchoTest.java000066400000000000000000000024371225554127700324100ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketEchoTest extends AbstractSocketEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/000077500000000000000000000000001225554127700263175ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/AbstractNioWorkerTest.java000066400000000000000000000037551225554127700334370ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import static org.easymock.EasyMock.*; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import org.jboss.netty.channel.ChannelFuture; import org.junit.Assert; import org.junit.Test; public abstract class AbstractNioWorkerTest { @Test public void testShutdownWorkerThrowsException() throws InterruptedException { AbstractNioChannel mockChannel = createMockChannel(); replay(mockChannel); ChannelFuture mockFuture = createMock(ChannelFuture.class); replay(mockFuture); ExecutorService executor = Executors.newCachedThreadPool(); AbstractNioWorker worker = createWorker(executor); worker.shutdown(); // give the Selector time to detect the shutdown Thread.sleep(SelectorUtil.DEFAULT_SELECT_TIMEOUT * 10); try { worker.register(mockChannel, mockFuture); Assert.fail(); } catch (RejectedExecutionException e) { // expected } verify(mockChannel, mockFuture); reset(mockChannel, mockFuture); } protected abstract AbstractNioWorker createWorker(Executor executor); protected abstract AbstractNioChannel createMockChannel(); } DefaultNioDatagramChannelConfigTest.java000066400000000000000000000053731225554127700360650ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.util.internal.DetectionUtil; import org.junit.Test; import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.StandardProtocolFamily; import java.nio.channels.DatagramChannel; import java.util.Enumeration; import static org.junit.Assert.*; public class DefaultNioDatagramChannelConfigTest { @Test public void testMulticastOptions() throws IOException { if (DetectionUtil.javaVersion() < 7 || DetectionUtil.isWindows()) { // Skip this test on java versions < 7 as its java7 only // and on windows as it may fail because of permission problems return; } StandardProtocolFamily family = null; NetworkInterface inf = null; Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { inf = interfaces.nextElement(); Enumeration addresses = inf.getInetAddresses(); while(addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); if (addr instanceof Inet4Address) { family = StandardProtocolFamily.INET; break; } else { family = StandardProtocolFamily.INET6; } } } if (inf == null) { // No usable interface found so just skip the test return; } DefaultNioDatagramChannelConfig config = new DefaultNioDatagramChannelConfig(DatagramChannel.open(family)); config.setNetworkInterface(inf); assertEquals(inf, config.getNetworkInterface()); InetAddress localhost = inf.getInetAddresses().nextElement(); config.setInterface(localhost); assertEquals(localhost, config.getInterface()); config.setTimeToLive(100); assertEquals(100, config.getTimeToLive()); config.setLoopbackModeDisabled(false); assertFalse(config.isLoopbackModeDisabled()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/NioDatagramWorkerTest.java000066400000000000000000000021071225554127700334020ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.easymock.EasyMock; import java.util.concurrent.Executor; public class NioDatagramWorkerTest extends AbstractNioWorkerTest { @Override protected AbstractNioWorker createWorker(Executor executor) { return new NioDatagramWorker(executor); } @Override protected AbstractNioChannel createMockChannel() { return EasyMock.createMock(NioDatagramChannel.class); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/NioServerBossPoolTest.java000066400000000000000000000032551225554127700334240ustar00rootroot00000000000000package org.jboss.netty.channel.socket.nio; import static org.junit.Assert.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class NioServerBossPoolTest { private static ExecutorService executor; @BeforeClass public static void init() { executor = Executors.newCachedThreadPool(); } @AfterClass public static void destroy() { ExecutorUtil.terminate(executor); } private static final String MY_CUSTOM_THREAD_NAME = "FOO"; private final ThreadNameDeterminer determiner = new ThreadNameDeterminer() { public String determineThreadName(String currentThreadName, String proposedThreadName) throws Exception { return MY_CUSTOM_THREAD_NAME; } }; @Test public void testNioServerBossPoolExecutorIntThreadNameDeterminer() throws Exception { NioServerBossPool bossPool = null; try { bossPool = new NioServerBossPool(executor, 1, determiner); NioServerBoss nextBoss = bossPool.nextBoss(); assertNotNull(nextBoss); // Wait for ThreadRenamingRunnable to be run by the executor Thread.sleep(1000); // Ok, now there should be thread assertNotNull(nextBoss.thread); assertEquals(MY_CUSTOM_THREAD_NAME, nextBoss.thread.getName()); } finally { if (bossPool != null) { bossPool.shutdown(); } } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/NioWorkerTest.java000066400000000000000000000020651225554127700317440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.easymock.EasyMock; import java.util.concurrent.Executor; public class NioWorkerTest extends AbstractNioWorkerTest { @Override protected AbstractNioWorker createWorker(Executor executor) { return new NioWorker(executor); } @Override protected AbstractNioChannel createMockChannel() { return EasyMock.createMock(NioSocketChannel.class); } } SocketReceiveBufferAllocatorTest.java000066400000000000000000000025261225554127700354760ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import static org.junit.Assert.*; import org.junit.Test; public class SocketReceiveBufferAllocatorTest { @Test public void testDecreaseBuffer() { SocketReceiveBufferAllocator allocator = new SocketReceiveBufferAllocator(2, 80); assertEquals(8192, allocator.get(8192).capacity()); assertEquals(8192, allocator.get(1024).capacity()); // Not 80% of the capacity so should just return the old buffer assertEquals(8192, allocator.get(8000).capacity()); assertEquals(8192, allocator.get(1024).capacity()); assertEquals(1024, allocator.get(1024).capacity()); allocator.releaseExternalResources(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/channel/socket/nio/UnsupportedMessageTest.java000066400000000000000000000100521225554127700336550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.channel.socket.nio; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; public class UnsupportedMessageTest { // Test for https://github.com/netty/netty/issues/734 @Test(timeout = 10000) public void testUnsupported() throws Throwable { ServerBootstrap sb = new ServerBootstrap(new NioServerSocketChannelFactory()); ClientBootstrap cb = new ClientBootstrap(new NioClientSocketChannelFactory()); TestHandler sh = new TestHandler(true); TestHandler ch = new TestHandler(false); sb.getPipeline().addLast("handler", sh); cb.getPipeline().addLast("handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); ccf.awaitUninterruptibly(); if (!ccf.isSuccess()) { sc.close().awaitUninterruptibly(); } assertTrue(ccf.isSuccess()); while (sh.channel == null) { Thread.sleep(10); } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); assertTrue(sh.await()); } private static class TestHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; private final boolean server; private final CountDownLatch latch; private final CountDownLatch exceptionLatch = new CountDownLatch(1); TestHandler(boolean server) { this.server = server; if (server) { latch = new CountDownLatch(1); } else { latch = null; } } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); if (server) { channel.write(new Object()).addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { latch.countDown(); } }); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { exceptionLatch.countDown(); e.getChannel().close(); } public boolean await() { if (latch == null) { return true; } try { return latch.await(5, TimeUnit.SECONDS) && exceptionLatch.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/000077500000000000000000000000001225554127700242475ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/000077500000000000000000000000001225554127700253245ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/000077500000000000000000000000001225554127700264165ustar00rootroot00000000000000AbstractSocketFixedLengthEchoTest.java000066400000000000000000000141751225554127700357070ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.jboss.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; public abstract class AbstractSocketFixedLengthEchoTest { private static final Random random = new Random(); static final byte[] data = new byte[1048576]; private static ExecutorService executor; static { random.nextBytes(data); } @BeforeClass public static void init() { executor = Executors.newCachedThreadPool(); } @AfterClass public static void destroy() { ExecutorUtil.terminate(executor); } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testFixedLengthEcho() throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(executor)); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(executor)); EchoHandler sh = new EchoHandler(); EchoHandler ch = new EchoHandler(); sb.getPipeline().addLast("decoder", new FixedLengthFrameDecoder(1024)); sb.getPipeline().addAfter("decoder", "handler", sh); cb.getPipeline().addLast("decoder", new FixedLengthFrameDecoder(1024)); cb.getPipeline().addAfter("decoder", "handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); Channel cc = cb.connect( new InetSocketAddress(TestUtil.getLocalHost(), port)).syncUninterruptibly().getChannel(); for (int i = 0; i < data.length;) { int length = Math.min(random.nextInt(1024 * 3), data.length - i); cc.write(ChannelBuffers.wrappedBuffer(data, i, length)); i += length; } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; EchoHandler() { } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer m = (ChannelBuffer) e.getMessage(); assertEquals(1024, m.readableBytes()); byte[] actual = new byte[m.readableBytes()]; m.getBytes(0, actual); int lastIdx = counter; for (int i = 0; i < actual.length; i ++) { assertEquals(data[i + lastIdx], actual[i]); } if (channel.getParent() != null) { channel.write(m); } counter += actual.length; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (exception.compareAndSet(null, e.getCause())) { e.getChannel().close(); } } } } DelimiterBasedFrameDecoderTest.java000066400000000000000000000066741225554127700351750ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; public class DelimiterBasedFrameDecoderTest { @Test public void testFailSlowTooLongFrameRecovery() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new DelimiterBasedFrameDecoder(1, Delimiters.nulDelimiter())); for (int i = 0; i < 2; i ++) { embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 1, 2 })); try { embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0 })); Assert.fail(CodecEmbedderException.class.getSimpleName() + " must be raised."); } catch (CodecEmbedderException e) { Assert.assertTrue(e.getCause() instanceof TooLongFrameException); // Expected } embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 'A', 0 })); ChannelBuffer buf = embedder.poll(); Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); } } @Test public void testFailFastTooLongFrameRecovery() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new DelimiterBasedFrameDecoder(1, true, true, Delimiters.nulDelimiter())); for (int i = 0; i < 2; i ++) { try { embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 1, 2 })); Assert.fail(CodecEmbedderException.class.getSimpleName() + " must be raised."); } catch (CodecEmbedderException e) { Assert.assertTrue(e.getCause() instanceof TooLongFrameException); // Expected } embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 'A', 0 })); ChannelBuffer buf = embedder.poll(); Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); } } @Test public void testDecode() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter())); Assert.assertTrue(embedder.offer(ChannelBuffers.copiedBuffer("first\r\nsecond\nthird", CharsetUtil.US_ASCII))); Assert.assertTrue(embedder.finish()); Assert.assertEquals("first", embedder.poll().toString(CharsetUtil.US_ASCII)); Assert.assertEquals("second", embedder.poll().toString(CharsetUtil.US_ASCII)); Assert.assertNull(embedder.poll()); } } LengthFieldBasedFrameDecoderTest.java000066400000000000000000000055211225554127700354320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; public class LengthFieldBasedFrameDecoderTest { @Test public void testFailSlowTooLongFrameRecovery() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4)); for (int i = 0; i < 2; i ++) { embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0, 0, 2 })); try { embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0 })); Assert.fail(CodecEmbedderException.class.getSimpleName() + " must be raised."); } catch (CodecEmbedderException e) { Assert.assertTrue(e.getCause() instanceof TooLongFrameException); // Expected } embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0, 0, 1, 'A' })); ChannelBuffer buf = embedder.poll(); Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); } } @Test public void testFailFastTooLongFrameRecovery() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4, true)); for (int i = 0; i < 2; i ++) { try { embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0, 0, 2 })); Assert.fail(CodecEmbedderException.class.getSimpleName() + " must be raised."); } catch (CodecEmbedderException e) { Assert.assertTrue(e.getCause() instanceof TooLongFrameException); // Expected } embedder.offer(ChannelBuffers.wrappedBuffer(new byte[] { 0, 0, 0, 0, 0, 1, 'A' })); ChannelBuffer buf = embedder.poll(); Assert.assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); } } } LineBasedFrameDecoderTest.java000066400000000000000000000113171225554127700341340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; import static org.hamcrest.CoreMatchers.*; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; public class LineBasedFrameDecoderTest { @Test public void testDecodeWithStrip() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LineBasedFrameDecoder(8192, true, false)); assertTrue(embedder.offer(copiedBuffer("first\r\nsecond\nthird", CharsetUtil.US_ASCII))); assertTrue(embedder.finish()); assertEquals("first", embedder.poll().toString(CharsetUtil.US_ASCII)); assertEquals("second", embedder.poll().toString(CharsetUtil.US_ASCII)); assertNull(embedder.poll()); } @Test public void testDecodeWithoutStrip() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LineBasedFrameDecoder(8192, false, false)); assertTrue(embedder.offer(copiedBuffer("first\r\nsecond\nthird", CharsetUtil.US_ASCII))); assertTrue(embedder.finish()); assertEquals("first\r\n", embedder.poll().toString(CharsetUtil.US_ASCII)); assertEquals("second\n", embedder.poll().toString(CharsetUtil.US_ASCII)); assertNull(embedder.poll()); } @Test public void testTooLongLine1() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LineBasedFrameDecoder(16, false, false)); try { embedder.offer(copiedBuffer("12345678901234567890\r\nfirst\nsecond", CharsetUtil.US_ASCII)); fail(); } catch (CodecEmbedderException e) { assertThat(e.getCause(), is(instanceOf(TooLongFrameException.class))); } embedder.offer(wrappedBuffer(new byte[1])); // A workaround that triggers decode() once again. assertThat(embedder.size(), is(1)); assertTrue(embedder.finish()); assertThat(embedder.size(), is(1)); assertThat(embedder.poll().toString(CharsetUtil.US_ASCII), is("first\n")); } @Test public void testTooLongLine2() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LineBasedFrameDecoder(16, false, false)); assertFalse(embedder.offer(copiedBuffer("12345678901234567", CharsetUtil.US_ASCII))); try { embedder.offer(copiedBuffer("890\r\nfirst\r\n", CharsetUtil.US_ASCII)); fail(); } catch (CodecEmbedderException e) { assertThat(e.getCause(), is(instanceOf(TooLongFrameException.class))); } embedder.offer(wrappedBuffer(new byte[1])); // A workaround that triggers decode() once again. assertThat(embedder.size(), is(1)); assertTrue(embedder.finish()); assertThat(embedder.size(), is(1)); assertEquals("first\r\n", embedder.poll().toString(CharsetUtil.US_ASCII)); } @Test public void testTooLongLineWithFailFast() throws Exception { DecoderEmbedder embedder = new DecoderEmbedder( new LineBasedFrameDecoder(16, false, true)); try { embedder.offer(copiedBuffer("12345678901234567", CharsetUtil.US_ASCII)); fail(); } catch (CodecEmbedderException e) { assertThat(e.getCause(), is(instanceOf(TooLongFrameException.class))); } assertThat(embedder.offer(copiedBuffer("890", CharsetUtil.US_ASCII)), is(false)); assertThat(embedder.offer(copiedBuffer("123\r\nfirst\r\n", CharsetUtil.US_ASCII)), is(true)); assertThat(embedder.size(), is(1)); assertTrue(embedder.finish()); assertThat(embedder.size(), is(1)); assertEquals("first\r\n", embedder.poll().toString(CharsetUtil.US_ASCII)); } } NioNioSocketFixedLengthEchoTest.java000066400000000000000000000025041225554127700353300ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } NioOioSocketFixedLengthEchoTest.java000066400000000000000000000025041225554127700353310ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } OioNioSocketFixedLengthEchoTest.java000066400000000000000000000024721225554127700353350ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; public class OioNioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } OioOioSocketFixedLengthEchoTest.java000066400000000000000000000024721225554127700353360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/frame/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.frame; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/000077500000000000000000000000001225554127700263035ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/CookieDecoderTest.java000066400000000000000000000467771225554127700325320ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.junit.Assert.*; import java.util.Date; import java.util.Iterator; import java.util.Set; import org.junit.Test; public class CookieDecoderTest { @Test public void testDecodingSingleCookieV0() { String cookieString = "myCookie=myValue;expires=XXX;path=/apathsomewhere;domain=.adomainsomewhere;secure;"; cookieString = cookieString.replace("XXX", HttpHeaderDateFormat.get().format(new Date(System.currentTimeMillis() + 50000))); CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); assertEquals(1, cookies.size()); Cookie cookie = cookies.iterator().next(); assertNotNull(cookie); assertEquals("myValue", cookie.getValue()); assertNull(cookie.getComment()); assertNull(cookie.getCommentUrl()); assertEquals(".adomainsomewhere", cookie.getDomain()); assertFalse(cookie.isDiscard()); boolean fail = true; for (int i = 40; i <= 60; i ++) { if (cookie.getMaxAge() == i) { fail = false; break; } } if (fail) { fail("expected: 50, actual: " + cookie.getMaxAge()); } assertEquals("/apathsomewhere", cookie.getPath()); assertTrue(cookie.getPorts().isEmpty()); assertTrue(cookie.isSecure()); assertEquals(0, cookie.getVersion()); } @Test public void testDecodingSingleCookieV0ExtraParamsIgnored() { String cookieString = "myCookie=myValue;max-age=50;path=/apathsomewhere;domain=.adomainsomewhere;secure;comment=this is a comment;version=0;commentURL=http://aurl.com;port=\"80,8080\";discard;"; CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); assertEquals(1, cookies.size()); Cookie cookie = cookies.iterator().next(); assertNotNull(cookie); assertEquals("myValue", cookie.getValue()); assertNull(cookie.getComment()); assertNull(cookie.getCommentUrl()); assertEquals(".adomainsomewhere", cookie.getDomain()); assertFalse(cookie.isDiscard()); assertEquals(50, cookie.getMaxAge()); assertEquals("/apathsomewhere", cookie.getPath()); assertTrue(cookie.getPorts().isEmpty()); assertTrue(cookie.isSecure()); assertEquals(0, cookie.getVersion()); } @Test public void testDecodingSingleCookieV1() { String cookieString = "myCookie=myValue;max-age=50;path=/apathsomewhere;domain=.adomainsomewhere;secure;comment=this is a comment;version=1;"; CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); assertEquals(1, cookies.size()); Cookie cookie = cookies.iterator().next(); assertEquals("myValue", cookie.getValue()); assertNotNull(cookie); assertEquals("this is a comment", cookie.getComment()); assertNull(cookie.getCommentUrl()); assertEquals(".adomainsomewhere", cookie.getDomain()); assertFalse(cookie.isDiscard()); assertEquals(50, cookie.getMaxAge()); assertEquals("/apathsomewhere", cookie.getPath()); assertTrue(cookie.getPorts().isEmpty()); assertTrue(cookie.isSecure()); assertEquals(1, cookie.getVersion()); } @Test public void testDecodingSingleCookieV1ExtraParamsIgnored() { String cookieString = "myCookie=myValue;max-age=50;path=/apathsomewhere;domain=.adomainsomewhere;secure;comment=this is a comment;version=1;commentURL=http://aurl.com;port='80,8080';discard;"; CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); assertEquals(1, cookies.size()); Cookie cookie = cookies.iterator().next(); assertNotNull(cookie); assertEquals("myValue", cookie.getValue()); assertEquals("this is a comment", cookie.getComment()); assertNull(cookie.getCommentUrl()); assertEquals(".adomainsomewhere", cookie.getDomain()); assertFalse(cookie.isDiscard()); assertEquals(50, cookie.getMaxAge()); assertEquals("/apathsomewhere", cookie.getPath()); assertTrue(cookie.getPorts().isEmpty()); assertTrue(cookie.isSecure()); assertEquals(1, cookie.getVersion()); } @Test public void testDecodingSingleCookieV2() { String cookieString = "myCookie=myValue;max-age=50;path=/apathsomewhere;domain=.adomainsomewhere;secure;comment=this is a comment;version=2;commentURL=http://aurl.com;port=\"80,8080\";discard;"; CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); assertEquals(1, cookies.size()); Cookie cookie = cookies.iterator().next(); assertNotNull(cookie); assertEquals("myValue", cookie.getValue()); assertEquals("this is a comment", cookie.getComment()); assertEquals("http://aurl.com", cookie.getCommentUrl()); assertEquals(".adomainsomewhere", cookie.getDomain()); assertTrue(cookie.isDiscard()); assertEquals(50, cookie.getMaxAge()); assertEquals("/apathsomewhere", cookie.getPath()); assertEquals(2, cookie.getPorts().size()); assertTrue(cookie.getPorts().contains(80)); assertTrue(cookie.getPorts().contains(8080)); assertTrue(cookie.isSecure()); assertEquals(2, cookie.getVersion()); } @Test public void testDecodingMultipleCookies() { String c1 = "myCookie=myValue;max-age=50;path=/apathsomewhere;domain=.adomainsomewhere;secure;comment=this is a comment;version=2;commentURL=\"http://aurl.com\";port='80,8080';discard;"; String c2 = "myCookie2=myValue2;max-age=0;path=/anotherpathsomewhere;domain=.anotherdomainsomewhere;comment=this is another comment;version=2;commentURL=http://anotherurl.com;"; String c3 = "myCookie3=myValue3;max-age=0;version=2;"; CookieDecoder decoder = new CookieDecoder(); Set cookies = decoder.decode(c1 + c2 + c3); assertEquals(3, cookies.size()); Iterator it = cookies.iterator(); Cookie cookie = it.next(); assertNotNull(cookie); assertEquals("myValue", cookie.getValue()); assertEquals("this is a comment", cookie.getComment()); assertEquals("http://aurl.com", cookie.getCommentUrl()); assertEquals(".adomainsomewhere", cookie.getDomain()); assertTrue(cookie.isDiscard()); assertEquals(50, cookie.getMaxAge()); assertEquals("/apathsomewhere", cookie.getPath()); assertEquals(2, cookie.getPorts().size()); assertTrue(cookie.getPorts().contains(80)); assertTrue(cookie.getPorts().contains(8080)); assertTrue(cookie.isSecure()); assertEquals(2, cookie.getVersion()); cookie = it.next(); assertNotNull(cookie); assertEquals("myValue2", cookie.getValue()); assertEquals("this is another comment", cookie.getComment()); assertEquals("http://anotherurl.com", cookie.getCommentUrl()); assertEquals(".anotherdomainsomewhere", cookie.getDomain()); assertFalse(cookie.isDiscard()); assertEquals(0, cookie.getMaxAge()); assertEquals("/anotherpathsomewhere", cookie.getPath()); assertTrue(cookie.getPorts().isEmpty()); assertFalse(cookie.isSecure()); assertEquals(2, cookie.getVersion()); cookie = it.next(); assertNotNull(cookie); assertEquals("myValue3", cookie.getValue()); assertNull( cookie.getComment()); assertNull(cookie.getCommentUrl()); assertNull(cookie.getDomain()); assertFalse(cookie.isDiscard()); assertEquals(0, cookie.getMaxAge()); assertNull(cookie.getPath()); assertTrue(cookie.getPorts().isEmpty()); assertFalse(cookie.isSecure()); assertEquals(2, cookie.getVersion()); } @Test public void testDecodingClientSideCookies() { String source = "$Version=\"1\"; " + "Part_Number=\"Riding_Rocket_0023\"; $Path=\"/acme/ammo\"; " + "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\""; Set cookies = new CookieDecoder().decode(source); Iterator it = cookies.iterator(); Cookie c; c = it.next(); assertEquals(1, c.getVersion()); assertEquals("Part_Number", c.getName()); assertEquals("Rocket_Launcher_0001", c.getValue()); assertEquals("/acme", c.getPath()); assertNull(c.getComment()); assertNull(c.getCommentUrl()); assertNull(c.getDomain()); assertTrue(c.getPorts().isEmpty()); assertEquals(Integer.MIN_VALUE, c.getMaxAge()); c = it.next(); assertEquals(1, c.getVersion()); assertEquals("Part_Number", c.getName()); assertEquals("Riding_Rocket_0023", c.getValue()); assertEquals("/acme/ammo", c.getPath()); assertNull(c.getComment()); assertNull(c.getCommentUrl()); assertNull(c.getDomain()); assertTrue(c.getPorts().isEmpty()); assertEquals(Integer.MIN_VALUE, c.getMaxAge()); assertFalse(it.hasNext()); } @Test public void testDecodingCommaSeparatedClientSideCookies() { String source = "$Version=\"1\"; session_id=\"1234\", " + "$Version=\"1\"; session_id=\"1111\"; $Domain=\".cracker.edu\""; Set cookies = new CookieDecoder().decode(source); Iterator it = cookies.iterator(); Cookie c; assertTrue(it.hasNext()); c = it.next(); assertEquals(1, c.getVersion()); assertEquals("session_id", c.getName()); assertEquals("1234", c.getValue()); assertNull(c.getPath()); assertNull(c.getComment()); assertNull(c.getCommentUrl()); assertNull(c.getDomain()); assertTrue(c.getPorts().isEmpty()); assertEquals(Integer.MIN_VALUE, c.getMaxAge()); assertTrue(it.hasNext()); c = it.next(); assertEquals(1, c.getVersion()); assertEquals("session_id", c.getName()); assertEquals("1111", c.getValue()); assertEquals(".cracker.edu", c.getDomain()); assertNull(c.getPath()); assertNull(c.getComment()); assertNull(c.getCommentUrl()); assertTrue(c.getPorts().isEmpty()); assertEquals(Integer.MIN_VALUE, c.getMaxAge()); assertFalse(it.hasNext()); } @Test public void testDecodingQuotedCookie() { String source = "a=\"\"," + "b=\"1\"," + "c=\"\\\"1\\\"2\\\"\"," + "d=\"1\\\"2\\\"3\"," + "e=\"\\\"\\\"\"," + "f=\"1\\\"\\\"2\"," + "g=\"\\\\\""; Set cookies = new CookieDecoder().decode(source); Iterator it = cookies.iterator(); Cookie c; c = it.next(); assertEquals("a", c.getName()); assertEquals("", c.getValue()); c = it.next(); assertEquals("b", c.getName()); assertEquals("1", c.getValue()); c = it.next(); assertEquals("c", c.getName()); assertEquals("\"1\"2\"", c.getValue()); c = it.next(); assertEquals("d", c.getName()); assertEquals("1\"2\"3", c.getValue()); c = it.next(); assertEquals("e", c.getName()); assertEquals("\"\"", c.getValue()); c = it.next(); assertEquals("f", c.getName()); assertEquals("1\"\"2", c.getValue()); c = it.next(); assertEquals("g", c.getName()); assertEquals("\\", c.getValue()); assertFalse(it.hasNext()); } @Test public void testDecodingGoogleAnalyticsCookie() { String source = "ARPT=LWUKQPSWRTUN04CKKJI; " + "kw-2E343B92-B097-442c-BFA5-BE371E0325A2=unfinished furniture; " + "__utma=48461872.1094088325.1258140131.1258140131.1258140131.1; " + "__utmb=48461872.13.10.1258140131; __utmc=48461872; " + "__utmz=48461872.1258140131.1.1.utmcsr=overstock.com|utmccn=(referral)|utmcmd=referral|utmcct=/Home-Garden/Furniture/Clearance,/clearance,/32/dept.html"; Set cookies = new CookieDecoder().decode(source); Iterator it = cookies.iterator(); Cookie c; c = it.next(); assertEquals("__utma", c.getName()); assertEquals("48461872.1094088325.1258140131.1258140131.1258140131.1", c.getValue()); c = it.next(); assertEquals("__utmb", c.getName()); assertEquals("48461872.13.10.1258140131", c.getValue()); c = it.next(); assertEquals("__utmc", c.getName()); assertEquals("48461872", c.getValue()); c = it.next(); assertEquals("__utmz", c.getName()); assertEquals("48461872.1258140131.1.1.utmcsr=overstock.com|utmccn=(referral)|utmcmd=referral|utmcct=/Home-Garden/Furniture/Clearance,/clearance,/32/dept.html", c.getValue()); c = it.next(); assertEquals("ARPT", c.getName()); assertEquals("LWUKQPSWRTUN04CKKJI", c.getValue()); c = it.next(); assertEquals("kw-2E343B92-B097-442c-BFA5-BE371E0325A2", c.getName()); assertEquals("unfinished furniture", c.getValue()); assertFalse(it.hasNext()); } @Test public void testDecodingWeirdNames1() { String src = "path=; expires=Mon, 01-Jan-1990 00:00:00 GMT; path=/; domain=.www.google.com"; Set cookies = new CookieDecoder().decode(src); Cookie c = cookies.iterator().next(); assertEquals("path", c.getName()); assertEquals("", c.getValue()); assertEquals("/", c.getPath()); } @Test public void testDecodingWeirdNames2() { String src = "HTTPOnly="; Set cookies = new CookieDecoder().decode(src); Cookie c = cookies.iterator().next(); assertEquals("HTTPOnly", c.getName()); assertEquals("", c.getValue()); } @Test public void testDecodingValuesWithCommasAndEquals() { String src = "A=v=1&lg=en-US,it-IT,it&intl=it&np=1;T=z=E"; Set cookies = new CookieDecoder().decode(src); Iterator i = cookies.iterator(); Cookie c = i.next(); assertEquals("A", c.getName()); assertEquals("v=1&lg=en-US,it-IT,it&intl=it&np=1", c.getValue()); c = i.next(); assertEquals("T", c.getName()); assertEquals("z=E", c.getValue()); } @Test public void testDecodingLongValue() { String longValue = "b!!!$Q!!$ha!!!!!!" + "%=J^wI!!3iD!!!!$=HbQW!!3iF!!!!#=J^wI!!3iH!!!!%=J^wI!!3iM!!!!%=J^wI!!3iS!!!!" + "#=J^wI!!3iU!!!!%=J^wI!!3iZ!!!!#=J^wI!!3i]!!!!%=J^wI!!3ig!!!!%=J^wI!!3ij!!!!" + "%=J^wI!!3ik!!!!#=J^wI!!3il!!!!$=HbQW!!3in!!!!%=J^wI!!3ip!!!!$=HbQW!!3iq!!!!" + "$=HbQW!!3it!!!!%=J^wI!!3ix!!!!#=J^wI!!3j!!!!!$=HbQW!!3j%!!!!$=HbQW!!3j'!!!!" + "%=J^wI!!3j(!!!!%=J^wI!!9mJ!!!!'=KqtH!!=SE!!M!!!!" + "'=KqtH!!s1X!!!!$=MMyc!!s1_!!!!#=MN#O!!ypn!!!!'=KqtH!!ypr!!!!'=KqtH!#%h!!!!!" + "%=KqtH!#%o!!!!!'=KqtH!#)H6!!!!!!'=KqtH!#]9R!!!!$=H/Lt!#]I6!!!!#=KqtH!#]Z#!!!!%=KqtH!#^*N!!!!" + "#=KqtH!#^:m!!!!#=KqtH!#_*_!!!!%=J^wI!#`-7!!!!#=KqtH!#`T>!!!!'=KqtH!#`T?!!!!" + "'=KqtH!#`TA!!!!'=KqtH!#`TB!!!!'=KqtH!#`TG!!!!'=KqtH!#`TP!!!!#=KqtH!#`U,!!!!" + "'=KqtH!#`U/!!!!'=KqtH!#`U0!!!!#=KqtH!#`U9!!!!'=KqtH!#aEQ!!!!%=KqtH!#b<)!!!!" + "'=KqtH!#c9-!!!!%=KqtH!#dxC!!!!%=KqtH!#dxE!!!!%=KqtH!#ev$!!!!'=KqtH!#fBi!!!!" + "#=KqtH!#fBj!!!!'=KqtH!#fG)!!!!'=KqtH!#fG+!!!!'=KqtH!#g*B!!!!'=KqtH!$>hD!!!!+=J^x0!$?lW!!!!'=KqtH!$?ll!!!!'=KqtH!$?lm!!!!" + "%=KqtH!$?mi!!!!'=KqtH!$?mx!!!!'=KqtH!$D7]!!!!#=J_#p!$D@T!!!!#=J_#p!$V cookies = new CookieDecoder().decode("bh=\"" + longValue + "\";"); assertEquals(1, cookies.size()); Cookie c = cookies.iterator().next(); assertEquals("bh", c.getName()); assertEquals(longValue, c.getValue()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/CookieEncoderTest.java000066400000000000000000000134311225554127700325210ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.junit.Assert.*; import java.text.DateFormat; import java.util.Date; import org.junit.Test; public class CookieEncoderTest { @Test public void testEncodingSingleCookieV0() { String result = "myCookie=myValue; Expires=XXX; Path=/apathsomewhere; Domain=.adomainsomewhere; Secure"; DateFormat df = HttpHeaderDateFormat.get(); Cookie cookie = new DefaultCookie("myCookie", "myValue"); CookieEncoder encoder = new CookieEncoder(true); encoder.addCookie(cookie); cookie.setComment("this is a Comment"); cookie.setCommentUrl("http://aurl.com"); cookie.setDomain(".adomainsomewhere"); cookie.setDiscard(true); cookie.setMaxAge(50); cookie.setPath("/apathsomewhere"); cookie.setPorts(80, 8080); cookie.setSecure(true); String encodedCookie = encoder.encode(); long currentTime = System.currentTimeMillis(); boolean fail = true; // +/- 10-second tolerance for (int delta = 0; delta <= 20000; delta += 250) { if (encodedCookie.equals(result.replace( "XXX", df.format(new Date(currentTime + 40000 + delta))))) { fail = false; break; } } if (fail) { fail("Expected: " + result + ", Actual: " + encodedCookie); } } @Test public void testEncodingSingleCookieV1() { String result = "myCookie=myValue; Max-Age=50; Path=\"/apathsomewhere\"; Domain=.adomainsomewhere; Secure; Comment=\"this is a Comment\"; Version=1"; Cookie cookie = new DefaultCookie("myCookie", "myValue"); CookieEncoder encoder = new CookieEncoder(true); encoder.addCookie(cookie); cookie.setVersion(1); cookie.setComment("this is a Comment"); cookie.setDomain(".adomainsomewhere"); cookie.setMaxAge(50); cookie.setPath("/apathsomewhere"); cookie.setSecure(true); String encodedCookie = encoder.encode(); assertEquals(result, encodedCookie); } @Test public void testEncodingSingleCookieV2() { String result = "myCookie=myValue; Max-Age=50; Path=\"/apathsomewhere\"; Domain=.adomainsomewhere; Secure; Comment=\"this is a Comment\"; Version=1; CommentURL=\"http://aurl.com\"; Port=\"80,8080\"; Discard"; Cookie cookie = new DefaultCookie("myCookie", "myValue"); CookieEncoder encoder = new CookieEncoder(true); encoder.addCookie(cookie); cookie.setVersion(1); cookie.setComment("this is a Comment"); cookie.setCommentUrl("http://aurl.com"); cookie.setDomain(".adomainsomewhere"); cookie.setDiscard(true); cookie.setMaxAge(50); cookie.setPath("/apathsomewhere"); cookie.setPorts(80, 8080); cookie.setSecure(true); String encodedCookie = encoder.encode(); assertEquals(result, encodedCookie); } @Test public void testEncodingMultipleServerCookies() { CookieEncoder encoder = new CookieEncoder(true); encoder.addCookie("a", "b"); encoder.addCookie("b", "c"); try { encoder.encode(); fail(); } catch (IllegalStateException e) { // Expected } } @Test public void testEncodingMultipleClientCookies() { String c1 = "$Version=1; myCookie=myValue; $Path=\"/apathsomewhere\"; $Domain=.adomainsomewhere; $Port=\"80,8080\"; "; String c2 = "$Version=1; myCookie2=myValue2; $Path=\"/anotherpathsomewhere\"; $Domain=.anotherdomainsomewhere; "; String c3 = "$Version=1; myCookie3=myValue3"; CookieEncoder encoder = new CookieEncoder(false); Cookie cookie = new DefaultCookie("myCookie", "myValue"); cookie.setVersion(1); cookie.setComment("this is a Comment"); cookie.setCommentUrl("http://aurl.com"); cookie.setDomain(".adomainsomewhere"); cookie.setDiscard(true); cookie.setMaxAge(50); cookie.setPath("/apathsomewhere"); cookie.setPorts(80, 8080); cookie.setSecure(true); encoder.addCookie(cookie); Cookie cookie2 = new DefaultCookie("myCookie2", "myValue2"); cookie2.setVersion(1); cookie2.setComment("this is another Comment"); cookie2.setCommentUrl("http://anotherurl.com"); cookie2.setDomain(".anotherdomainsomewhere"); cookie2.setDiscard(false); cookie2.setPath("/anotherpathsomewhere"); cookie2.setSecure(false); encoder.addCookie(cookie2); Cookie cookie3 = new DefaultCookie("myCookie3", "myValue3"); cookie3.setVersion(1); encoder.addCookie(cookie3); String encodedCookie = encoder.encode(); assertEquals(c1 +c2 + c3, encodedCookie); } @Test public void testEncodingWithNoCookies() { CookieEncoder encoderForServer = new CookieEncoder(true); String encodedCookie1 = encoderForServer.encode(); CookieEncoder encoderForClient = new CookieEncoder(false); String encodedCookie2 = encoderForClient.encode(); assertNotNull(encodedCookie1); assertNotNull(encodedCookie2); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/DefaultHttpMessageTest.java000066400000000000000000000027301225554127700335410ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.junit.Assert; import org.junit.Test; public class DefaultHttpMessageTest { @Test public void testHeaderRemoval() { HttpMessage m = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, "/"); // Insert sample keys. for (int i = 0; i < 1000; i ++) { m.headers().set(String.valueOf(i), ""); } // Remove in reversed order. for (int i = 999; i >= 0; i --) { m.headers().remove(String.valueOf(i)); } // Check if random access returns nothing. for (int i = 0; i < 1000; i ++) { Assert.assertNull(m.headers().get(String.valueOf(i))); } // Check if sequential access returns nothing. Assert.assertTrue(m.headers().entries().isEmpty()); } } HttpChunkAggregatorTest.java000066400000000000000000000214111225554127700336410ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.easymock.EasyMock; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.CompositeChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; import java.util.List; import static org.junit.Assert.*; public class HttpChunkAggregatorTest { @Test public void testAggregate() { HttpChunkAggregator aggr = new HttpChunkAggregator(1024 * 1024); DecoderEmbedder embedder = new DecoderEmbedder(aggr); HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1); message.headers().set("X-Test", true); message.setChunked(true); HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII)); HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII)); HttpChunk chunk3 = new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER); assertFalse(embedder.offer(message)); assertFalse(embedder.offer(chunk1)); assertFalse(embedder.offer(chunk2)); // this should trigger a messageReceived event so return true assertTrue(embedder.offer(chunk3)); assertTrue(embedder.finish()); HttpMessage aggratedMessage = embedder.poll(); assertNotNull(aggratedMessage); assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage)); assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString()); checkContentBuffer(aggratedMessage); assertNull(embedder.poll()); } private static void checkContentBuffer(HttpMessage aggregatedMessage) { CompositeChannelBuffer buffer = (CompositeChannelBuffer) aggregatedMessage.getContent(); assertEquals(2, buffer.numComponents()); List buffers = buffer.decompose(0, buffer.capacity()); assertEquals(2, buffers.size()); for (ChannelBuffer buf: buffers) { // This should be false as we decompose the buffer before to not have deep hierarchy assertFalse(buf instanceof CompositeChannelBuffer); } } @Test public void testAggregateWithTrailer() { HttpChunkAggregator aggr = new HttpChunkAggregator(1024 * 1024); DecoderEmbedder embedder = new DecoderEmbedder(aggr); HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1); message.headers().set("X-Test", true); message.setChunked(true); HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII)); HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII)); HttpChunkTrailer trailer = new DefaultHttpChunkTrailer(); trailer.trailingHeaders().set("X-Trailer", true); assertFalse(embedder.offer(message)); assertFalse(embedder.offer(chunk1)); assertFalse(embedder.offer(chunk2)); // this should trigger a messageReceived event so return true assertTrue(embedder.offer(trailer)); assertTrue(embedder.finish()); HttpMessage aggratedMessage = embedder.poll(); assertNotNull(aggratedMessage); assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage)); assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString()); assertEquals(aggratedMessage.headers().get("X-Trailer"), Boolean.TRUE.toString()); checkContentBuffer(aggratedMessage); assertNull(embedder.poll()); } @Test public void testTooLongFrameException() { HttpChunkAggregator aggr = new HttpChunkAggregator(4); DecoderEmbedder embedder = new DecoderEmbedder(aggr); HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1); message.setChunked(true); HttpMessage message2= new DefaultHttpMessage(HttpVersion.HTTP_1_1); message2.setChunked(true); HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII)); HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII)); HttpChunk chunk3 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test3", CharsetUtil.US_ASCII)); HttpChunk chunk4 = HttpChunk.LAST_CHUNK; HttpChunk chunk5 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII)); HttpChunk chunk6 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII)); HttpChunk chunk7 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test3", CharsetUtil.US_ASCII)); HttpChunk chunk8 = HttpChunk.LAST_CHUNK; assertFalse(embedder.offer(message)); assertFalse(embedder.offer(chunk1)); try { embedder.offer(chunk2); fail(); } catch (CodecEmbedderException e) { assertTrue(e.getCause() instanceof TooLongFrameException); } assertFalse(embedder.offer(chunk3)); assertFalse(embedder.offer(chunk4)); assertFalse(embedder.offer(message2)); assertFalse(embedder.offer(chunk5)); try { embedder.offer(chunk6); fail(); } catch (CodecEmbedderException e) { assertTrue(e.getCause() instanceof TooLongFrameException); } assertFalse(embedder.offer(chunk7)); assertFalse(embedder.offer(chunk8)); } @Test(expected = IllegalArgumentException.class) public void testInvalidConstructorUsage() { new HttpChunkAggregator(0); } @Test(expected = IllegalArgumentException.class) public void testInvalidMaxCumulationBufferComponents() { HttpChunkAggregator aggr= new HttpChunkAggregator(Integer.MAX_VALUE); aggr.setMaxCumulationBufferComponents(1); } @Test(expected = IllegalStateException.class) public void testSetMaxCumulationBufferComponentsAfterInit() throws Exception { HttpChunkAggregator aggr = new HttpChunkAggregator(Integer.MAX_VALUE); ChannelHandlerContext ctx = EasyMock.createMock(ChannelHandlerContext.class); EasyMock.replay(ctx); aggr.beforeAdd(ctx); aggr.setMaxCumulationBufferComponents(10); } @Test public void testAggregateTransferEncodingChunked() { HttpChunkAggregator aggr = new HttpChunkAggregator(1024 * 1024); DecoderEmbedder embedder = new DecoderEmbedder(aggr); HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1); message.headers().set("X-Test", true); message.headers().set("Transfer-Encoding", "Chunked"); message.setChunked(true); HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII)); HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII)); HttpChunk chunk3 = new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER); assertFalse(embedder.offer(message)); assertFalse(embedder.offer(chunk1)); assertFalse(embedder.offer(chunk2)); // this should trigger a messageReceived event so return true assertTrue(embedder.offer(chunk3)); assertTrue(embedder.finish()); HttpMessage aggratedMessage = embedder.poll(); assertNotNull(aggratedMessage); assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage)); assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString()); checkContentBuffer(aggratedMessage); assertNull(embedder.poll()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/HttpClientCodecTest.java000066400000000000000000000101631225554127700330230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.junit.Assert.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.PrematureChannelClosureException; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; public class HttpClientCodecTest { private static final String RESPONSE = "HTTP/1.0 200 OK\r\n" + "Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 28\r\n" + "\r\n" + "\r\n"; private static final String INCOMPLETE_CHUNKED_RESPONSE = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" +"5\r\n" + "first\r\n" + "6\r\n" + "second\r\n" + "0\r\n"; private static final String CHUNKED_RESPONSE = INCOMPLETE_CHUNKED_RESPONSE + "\r\n"; @Test public void testFailsNotOnRequestResponse() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); DecoderEmbedder decoder = new DecoderEmbedder(codec); EncoderEmbedder encoder = new EncoderEmbedder(codec); encoder.offer(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); decoder.offer(ChannelBuffers.copiedBuffer(RESPONSE, CharsetUtil.ISO_8859_1)); encoder.finish(); decoder.finish(); } @Test public void testFailsNotOnRequestResponseChunked() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); DecoderEmbedder decoder = new DecoderEmbedder(codec); EncoderEmbedder encoder = new EncoderEmbedder(codec); encoder.offer(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); decoder.offer(ChannelBuffers.copiedBuffer(CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1)); encoder.finish(); decoder.finish(); } @Test public void testFailsOnMissingResponse() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); EncoderEmbedder encoder = new EncoderEmbedder(codec); encoder.offer(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); try { encoder.finish(); fail(); } catch (CodecEmbedderException e) { assertTrue(e.getCause() instanceof PrematureChannelClosureException); } } @Test public void testFailsOnIncompleteChunkedResponse() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); DecoderEmbedder decoder = new DecoderEmbedder(codec); EncoderEmbedder encoder = new EncoderEmbedder(codec); encoder.offer(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); decoder.offer(ChannelBuffers.copiedBuffer(INCOMPLETE_CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1)); try { encoder.finish(); decoder.finish(); fail(); } catch (CodecEmbedderException e) { assertTrue(e.getCause() instanceof PrematureChannelClosureException); } } } HttpContentCompressorTest.java000066400000000000000000000034061225554127700342610ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.junit.Assert; import org.junit.Test; public class HttpContentCompressorTest { @Test public void testGetTargetContentEncoding() throws Exception { HttpContentCompressor compressor = new HttpContentCompressor(); String[] tests = { // Accept-Encoding -> Content-Encoding "", null, "*", "gzip", "*;q=0.0", null, "gzip", "gzip", "compress, gzip;q=0.5", "gzip", "gzip; q=0.5, identity", "gzip", "gzip ; q=0.1", "gzip", "gzip; q=0, deflate", "deflate", " deflate ; q=0 , *;q=0.5", "gzip", }; for (int i = 0; i < tests.length; i += 2) { String acceptEncoding = tests[i]; String contentEncoding = tests[i + 1]; String targetEncoding = compressor.getTargetContentEncoding(acceptEncoding); Assert.assertEquals(contentEncoding, targetEncoding); } } } HttpHeaderDateFormatTest.java000066400000000000000000000053511225554127700337320ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.text.ParseException; import java.util.Date; import org.junit.Assert; import org.junit.Test; public class HttpHeaderDateFormatTest { /** * This date is set at "06 Nov 1994 08:49:37 GMT" (same used in example in * RFC documentation) *

* http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html */ private static final Date DATE = new Date(784111777000L); @Test public void testParse() throws ParseException { HttpHeaderDateFormat format = HttpHeaderDateFormat.get(); final Date parsedDateWithSingleDigitDay = format.parse("Sun, 6 Nov 1994 08:49:37 GMT"); Assert.assertNotNull(parsedDateWithSingleDigitDay); Assert.assertEquals(DATE, parsedDateWithSingleDigitDay); final Date parsedDateWithDoubleDigitDay = format.parse("Sun, 06 Nov 1994 08:49:37 GMT"); Assert.assertNotNull(parsedDateWithDoubleDigitDay); Assert.assertEquals(DATE, parsedDateWithDoubleDigitDay); final Date parsedDateWithDashSeparatorSingleDigitDay = format.parse("Sunday, 06-Nov-94 08:49:37 GMT"); Assert.assertNotNull(parsedDateWithDashSeparatorSingleDigitDay); Assert.assertEquals(DATE, parsedDateWithDashSeparatorSingleDigitDay); final Date parsedDateWithSingleDoubleDigitDay = format.parse("Sunday, 6-Nov-94 08:49:37 GMT"); Assert.assertNotNull(parsedDateWithSingleDoubleDigitDay); Assert.assertEquals(DATE, parsedDateWithSingleDoubleDigitDay); final Date parsedDateWithoutGMT = format.parse("Sun Nov 6 08:49:37 1994"); Assert.assertNotNull(parsedDateWithoutGMT); Assert.assertEquals(DATE, parsedDateWithoutGMT); } private Date parseDate(HttpHeaderDateFormat dateFormat, String dateStr) throws ParseException { return dateFormat.parse(dateStr); } @Test public void testFormat() { HttpHeaderDateFormat format = HttpHeaderDateFormat.get(); final String formatted = format.format(DATE); Assert.assertNotNull(formatted); Assert.assertEquals("Sun, 06 Nov 1994 08:49:37 GMT", formatted); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/HttpMessageEncoderTest.java000066400000000000000000000026421225554127700335360ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.junit.Assert.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.junit.Test; public class HttpMessageEncoderTest { // Test for #493 @Test public void testHttpChunkIsLast() { EncoderEmbedder encoder = new EncoderEmbedder(new HttpMessageEncoder() { @Override protected void encodeInitialLine(ChannelBuffer buf, HttpMessage message) throws Exception { // do nothing } }); assertTrue(encoder.offer(HttpChunk.LAST_CHUNK)); assertTrue(encoder.finish()); assertNotNull(encoder.poll()); assertNull(encoder.poll()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/HttpRequestEncoderTest.java000066400000000000000000000034311225554127700335770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import static org.junit.Assert.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Test; import java.nio.charset.Charset; /** */ public class HttpRequestEncoderTest { @Test public void testUriWithoutPath() throws Exception { HttpRequestEncoder encoder = new HttpRequestEncoder(); ChannelBuffer buffer = ChannelBuffers.buffer(64); encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost")); String req = buffer.toString(Charset.forName("US-ASCII")); assertEquals("GET http://localhost/ HTTP/1.1\r\n", req); } @Test public void testUriWithPath() throws Exception { HttpRequestEncoder encoder = new HttpRequestEncoder(); ChannelBuffer buffer = ChannelBuffers.buffer(64); encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); String req = buffer.toString(Charset.forName("US-ASCII")); assertEquals("GET http://localhost/ HTTP/1.1\r\n", req); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/HttpServerCodecTest.java000066400000000000000000000050351225554127700330550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; public class HttpServerCodecTest { /** * Testcase for https://github.com/netty/netty/issues/433 */ @Test public void testUnfinishedChunkedHttpRequestIsLastFlag() throws Exception { int maxChunkSize = 2000; HttpServerCodec httpServerCodec = new HttpServerCodec(1000, 1000, maxChunkSize); DecoderEmbedder decoderEmbedder = new DecoderEmbedder(httpServerCodec); int totalContentLength = maxChunkSize * 5; decoderEmbedder.offer(ChannelBuffers.copiedBuffer("PUT /test HTTP/1.1\r\n" + "Content-Length: " + totalContentLength + "\r\n" + "\r\n", CharsetUtil.UTF_8)); int offeredContentLength = (int) (maxChunkSize * 2.5); decoderEmbedder.offer(prepareDataChunk(offeredContentLength)); decoderEmbedder.finish(); HttpMessage httpMessage = (HttpMessage) decoderEmbedder.poll(); Assert.assertTrue(httpMessage.isChunked()); Assert.assertNotNull(decoderEmbedder.peek()); int totalBytesPolled = 0; while (decoderEmbedder.peek() != null) { HttpChunk httpChunk = (HttpChunk) decoderEmbedder.poll(); totalBytesPolled += httpChunk.getContent().readableBytes(); Assert.assertFalse(httpChunk.isLast()); } Assert.assertEquals(offeredContentLength, totalBytesPolled); } private static ChannelBuffer prepareDataChunk(int size) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < size; ++i) { sb.append('a'); } return ChannelBuffers.copiedBuffer(sb.toString(), CharsetUtil.UTF_8); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/QueryStringDecoderTest.java000066400000000000000000000272551225554127700336030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http; import java.net.URI; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.jboss.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; public class QueryStringDecoderTest { @Test public void testBasic() throws Exception { QueryStringDecoder d; d = new QueryStringDecoder("/foo?a=b=c"); Assert.assertEquals("/foo", d.getPath()); Assert.assertEquals(1, d.getParameters().size()); Assert.assertEquals(1, d.getParameters().get("a").size()); Assert.assertEquals("b=c", d.getParameters().get("a").get(0)); d = new QueryStringDecoder("/foo?a=1&a=2"); Assert.assertEquals("/foo", d.getPath()); Assert.assertEquals(1, d.getParameters().size()); Assert.assertEquals(2, d.getParameters().get("a").size()); Assert.assertEquals("1", d.getParameters().get("a").get(0)); Assert.assertEquals("2", d.getParameters().get("a").get(1)); d = new QueryStringDecoder("/foo?a=&a=2"); Assert.assertEquals("/foo", d.getPath()); Assert.assertEquals(1, d.getParameters().size()); Assert.assertEquals(2, d.getParameters().get("a").size()); Assert.assertEquals("", d.getParameters().get("a").get(0)); Assert.assertEquals("2", d.getParameters().get("a").get(1)); d = new QueryStringDecoder("/foo?a=1&a="); Assert.assertEquals("/foo", d.getPath()); Assert.assertEquals(1, d.getParameters().size()); Assert.assertEquals(2, d.getParameters().get("a").size()); Assert.assertEquals("1", d.getParameters().get("a").get(0)); Assert.assertEquals("", d.getParameters().get("a").get(1)); d = new QueryStringDecoder("/foo?a=1&a=&a="); Assert.assertEquals("/foo", d.getPath()); Assert.assertEquals(1, d.getParameters().size()); Assert.assertEquals(3, d.getParameters().get("a").size()); Assert.assertEquals("1", d.getParameters().get("a").get(0)); Assert.assertEquals("", d.getParameters().get("a").get(1)); Assert.assertEquals("", d.getParameters().get("a").get(2)); d = new QueryStringDecoder("/foo?a=1=&a==2"); Assert.assertEquals("/foo", d.getPath()); Assert.assertEquals(1, d.getParameters().size()); Assert.assertEquals(2, d.getParameters().get("a").size()); Assert.assertEquals("1=", d.getParameters().get("a").get(0)); Assert.assertEquals("=2", d.getParameters().get("a").get(1)); } @Test public void testExotic() throws Exception { assertQueryString("", ""); assertQueryString("foo", "foo"); assertQueryString("/foo", "/foo"); assertQueryString("?a=", "?a"); assertQueryString("foo?a=", "foo?a"); assertQueryString("/foo?a=", "/foo?a"); assertQueryString("/foo?a=", "/foo?a&"); assertQueryString("/foo?a=", "/foo?&a"); assertQueryString("/foo?a=", "/foo?&a&"); assertQueryString("/foo?a=", "/foo?&=a"); assertQueryString("/foo?a=", "/foo?=a&"); assertQueryString("/foo?a=", "/foo?a=&"); assertQueryString("/foo?a=b&c=d", "/foo?a=b&&c=d"); assertQueryString("/foo?a=b&c=d", "/foo?a=b&=&c=d"); assertQueryString("/foo?a=b&c=d", "/foo?a=b&==&c=d"); assertQueryString("/foo?a=b&c=&x=y", "/foo?a=b&c&x=y"); assertQueryString("/foo?a=", "/foo?a="); assertQueryString("/foo?a=", "/foo?&a="); assertQueryString("/foo?a=b&c=d", "/foo?a=b&c=d"); assertQueryString("/foo?a=1&a=&a=", "/foo?a=1&a&a="); } @Test public void testHashDos() throws Exception { StringBuilder buf = new StringBuilder(); buf.append('?'); for (int i = 0; i < 65536; i ++) { buf.append('k'); buf.append(i); buf.append("=v"); buf.append(i); buf.append('&'); } Assert.assertEquals(1024, new QueryStringDecoder(buf.toString()).getParameters().size()); } @Test public void testHasPath() throws Exception { QueryStringDecoder decoder = new QueryStringDecoder("1=2", false); Assert.assertEquals("", decoder.getPath()); Map> params = decoder.getParameters(); Assert.assertEquals(1, params.size()); Assert.assertTrue(params.containsKey("1")); List param = params.get("1"); Assert.assertNotNull(param); Assert.assertEquals(1, param.size()); Assert.assertEquals("2", param.get(0)); } @Test public void testUrlDecoding() throws Exception { final String caffe = new String( // "Caffé" but instead of putting the literal E-acute in the // source file, we directly use the UTF-8 encoding so as to // not rely on the platform's default encoding (not portable). new byte[] {'C', 'a', 'f', 'f', (byte) 0xC3, (byte) 0xA9}, "UTF-8"); final String[] tests = { // Encoded -> Decoded or error message substring "", "", "foo", "foo", "f%%b", "f%b", "f+o", "f o", "f++", "f ", "fo%", "unterminated escape sequence", "%42", "B", "%5f", "_", "f%4", "partial escape sequence", "%x2", "invalid escape sequence `%x2' at index 0 of: %x2", "%4x", "invalid escape sequence `%4x' at index 0 of: %4x", "Caff%C3%A9", caffe, }; for (int i = 0; i < tests.length; i += 2) { final String encoded = tests[i]; final String expected = tests[i + 1]; try { final String decoded = QueryStringDecoder.decodeComponent(encoded); Assert.assertEquals(expected, decoded); } catch (IllegalArgumentException e) { Assert.assertTrue("String \"" + e.getMessage() + "\" does" + " not contain \"" + expected + '"', e.getMessage().contains(expected)); } } } private static void assertQueryString(String expected, String actual) { QueryStringDecoder ed = new QueryStringDecoder(expected, CharsetUtil.UTF_8); QueryStringDecoder ad = new QueryStringDecoder(actual, CharsetUtil.UTF_8); Assert.assertEquals(ed.getPath(), ad.getPath()); Assert.assertEquals(ed.getParameters(), ad.getParameters()); } // See #189 @Test public void testURI() { URI uri = URI.create("http://localhost:8080/foo?param1=value1¶m2=value2¶m3=value3"); QueryStringDecoder decoder = new QueryStringDecoder(uri); Assert.assertEquals("/foo", decoder.getPath()); Map> params = decoder.getParameters(); Assert.assertEquals(3, params.size()); Iterator>> entries = params.entrySet().iterator(); Entry> entry = entries.next(); Assert.assertEquals("param1", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value1", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("param2", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value2", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("param3", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value3", entry.getValue().get(0)); Assert.assertFalse(entries.hasNext()); } // See #189 @Test public void testURISlashPath() { URI uri = URI.create("http://localhost:8080/?param1=value1¶m2=value2¶m3=value3"); QueryStringDecoder decoder = new QueryStringDecoder(uri); Assert.assertEquals("/", decoder.getPath()); Map> params = decoder.getParameters(); Assert.assertEquals(3, params.size()); Iterator>> entries = params.entrySet().iterator(); Entry> entry = entries.next(); Assert.assertEquals("param1", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value1", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("param2", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value2", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("param3", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value3", entry.getValue().get(0)); Assert.assertFalse(entries.hasNext()); } // See #189 @Test public void testURINoPath() { URI uri = URI.create("http://localhost:8080?param1=value1¶m2=value2¶m3=value3"); QueryStringDecoder decoder = new QueryStringDecoder(uri); Assert.assertEquals("", decoder.getPath()); Map> params = decoder.getParameters(); Assert.assertEquals(3, params.size()); Iterator>> entries = params.entrySet().iterator(); Entry> entry = entries.next(); Assert.assertEquals("param1", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value1", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("param2", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value2", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("param3", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("value3", entry.getValue().get(0)); Assert.assertFalse(entries.hasNext()); } // See https://github.com/netty/netty/issues/1833 @Test public void testURI2() { URI uri = URI.create("http://foo.com/images;num=10?query=name;value=123"); QueryStringDecoder decoder = new QueryStringDecoder(uri); Assert.assertEquals("/images;num=10", decoder.getPath()); Map> params = decoder.getParameters(); Assert.assertEquals(2, params.size()); Iterator>> entries = params.entrySet().iterator(); Entry> entry = entries.next(); Assert.assertEquals("query", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("name", entry.getValue().get(0)); entry = entries.next(); Assert.assertEquals("value", entry.getKey()); Assert.assertEquals(1, entry.getValue().size()); Assert.assertEquals("123", entry.getValue().get(0)); Assert.assertFalse(entries.hasNext()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/multipart/000077500000000000000000000000001225554127700303245ustar00rootroot00000000000000AbstractMemoryHttpDataTest.java000066400000000000000000000060051225554127700363370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffer; import org.junit.Test; import java.io.ByteArrayInputStream; import java.nio.charset.Charset; import java.security.SecureRandom; import java.util.Arrays; import java.util.Random; import static org.jboss.netty.util.CharsetUtil.*; import static org.junit.Assert.*; /** {@link AbstractMemoryHttpData} test cases. */ public class AbstractMemoryHttpDataTest { /** * Provide content into HTTP data with input stream. * * @throws Exception In case of any exception. */ @Test public void testSetContentFromStream() throws Exception { Random random = new SecureRandom(); for (int i = 0; i < 20; i++) { // Generate input data bytes. int size = random.nextInt(Short.MAX_VALUE); byte[] bytes = new byte[size]; random.nextBytes(bytes); // Generate parsed HTTP data block. TestHttpData data = new TestHttpData("name", UTF_8, 0); data.setContent(new ByteArrayInputStream(bytes)); // Validate stored data. ChannelBuffer buffer = data.getChannelBuffer(); assertEquals(0, buffer.readerIndex()); assertEquals(bytes.length, buffer.writerIndex()); assertArrayEquals(bytes, Arrays.copyOf(buffer.array(), bytes.length)); } } /** Memory-based HTTP data implementation for test purposes. */ private static final class TestHttpData extends AbstractMemoryHttpData { /** * Constructs HTTP data for tests. * * @param name Name of parsed data block. * @param charset Used charset for data decoding. * @param size Expected data block size. */ protected TestHttpData(String name, Charset charset, long size) { super(name, charset, size); } public InterfaceHttpData.HttpDataType getHttpDataType() { throw new UnsupportedOperationException("Should never be called."); } public int compareTo(InterfaceHttpData o) { throw new UnsupportedOperationException("Should never be called."); } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { return super.equals(obj); } } } HttpPostRequestDecoderTest.java000066400000000000000000000060641225554127700364020ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/multipart/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.http.multipart; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.DefaultHttpChunk; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; import java.util.Arrays; import static org.junit.Assert.*; /** {@link HttpPostRequestDecoder} test case. */ public class HttpPostRequestDecoderTest { @Test public void testBinaryStreamUpload() throws Exception { final String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; final DefaultHttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "http://localhost"); req.setContent(ChannelBuffers.EMPTY_BUFFER); req.headers().set(HttpHeaders.Names.CONTENT_TYPE, "multipart/form-data; boundary=" + boundary); req.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); req.setChunked(true); // Force to use memory-based data. final DefaultHttpDataFactory inMemoryFactory = new DefaultHttpDataFactory(false); for (String data : Arrays.asList("", "\r", "\r\r", "\r\r\r")) { final String body = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"tmp-0.txt\"\r\n" + "Content-Type: image/gif\r\n" + "\r\n" + data + "\r\n" + "--" + boundary + "--\r\n"; // Create decoder instance to test. final HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(inMemoryFactory, req); decoder.offer(new DefaultHttpChunk(ChannelBuffers.copiedBuffer(body, CharsetUtil.UTF_8))); decoder.offer(new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER)); // Validate it's enough chunks to decode upload. assertTrue(decoder.hasNext()); // Decode binary upload. MemoryFileUpload upload = (MemoryFileUpload) decoder.next(); // Validate data has been parsed correctly as it was passed into request. assertArrayEquals("Invalid decoded data [data=" + data + "upload=" + upload + ']', data.getBytes(), upload.get()); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/websocketx/000077500000000000000000000000001225554127700304615ustar00rootroot00000000000000WebSocketRequestBuilder.java000066400000000000000000000077211225554127700360220ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jboss.netty.handler.codec.http.websocketx; import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.handler.codec.http.HttpHeaders.Names; public class WebSocketRequestBuilder { private HttpVersion httpVersion; private HttpMethod method; private String uri; private String host; private String upgrade; private String connection; private String key; private String origin; private WebSocketVersion version; public WebSocketRequestBuilder httpVersion(HttpVersion httpVersion) { this.httpVersion = httpVersion; return this; } public WebSocketRequestBuilder method(HttpMethod method) { this.method = method; return this; } public WebSocketRequestBuilder uri(String uri) { this.uri = uri; return this; } public WebSocketRequestBuilder host(String host) { this.host = host; return this; } public WebSocketRequestBuilder upgrade(String upgrade) { this.upgrade = upgrade; return this; } public WebSocketRequestBuilder connection(String connection) { this.connection = connection; return this; } public WebSocketRequestBuilder key(String key) { this.key = key; return this; } public WebSocketRequestBuilder origin(String origin) { this.origin = origin; return this; } public WebSocketRequestBuilder version13() { version = WebSocketVersion.V13; return this; } public WebSocketRequestBuilder version8() { version = WebSocketVersion.V08; return this; } public WebSocketRequestBuilder version00() { version = null; return this; } public WebSocketRequestBuilder noVersion() { return this; } public HttpRequest build() { HttpRequest req = new DefaultHttpRequest(httpVersion, method, uri); if (host != null) { req.headers().set(Names.HOST, host); } if (upgrade != null) { req.headers().set(Names.UPGRADE, upgrade); } if (connection != null) { req.headers().set(Names.CONNECTION, connection); } if (key != null) { req.headers().set(Names.SEC_WEBSOCKET_KEY, key); } if (origin != null) { req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, origin); } if (version != null) { req.headers().set(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue()); } return req; } public static HttpRequest sucessful() { return new WebSocketRequestBuilder().httpVersion(HTTP_1_1) .method(HttpMethod.GET) .uri("/test") .host("server.example.com") .upgrade(WEBSOCKET.toLowerCase()) .key("dGhlIHNhbXBsZSBub25jZQ==") .origin("http://example.com") .version13() .build(); } } WebSocketServerProtocolHandlerTest.java000066400000000000000000000151751225554127700402130ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.junit.Test; import java.util.LinkedList; import java.util.Queue; import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.*; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*; import static org.jboss.netty.handler.codec.http.HttpVersion.*; import static org.junit.Assert.*; public class WebSocketServerProtocolHandlerTest { @Test public void testHttpUpgradeRequest() { DecoderEmbedder embedder = decoderEmbedder(); ChannelHandlerContext ctx = embedder.getPipeline().getContext(WebSocketServerProtocolHandshakeHandler.class); HttpResponseInterceptor responseInterceptor = addHttpResponseInterceptor(embedder); embedder.offer(WebSocketRequestBuilder.sucessful()); HttpResponse response = responseInterceptor.getHttpResponse(); assertEquals(SWITCHING_PROTOCOLS, response.getStatus()); assertNotNull(WebSocketServerProtocolHandler.getHandshaker(ctx)); } private static HttpResponseInterceptor addHttpResponseInterceptor(DecoderEmbedder embedder) { HttpResponseInterceptor interceptor = new HttpResponseInterceptor(); embedder.getPipeline().addLast("httpEncoder", interceptor); return interceptor; } @Test public void testSubsequentHttpRequestsAfterUpgradeShouldReturn403() throws Exception { DecoderEmbedder embedder = decoderEmbedder(); HttpResponseInterceptor responseInterceptor = addHttpResponseInterceptor(embedder); embedder.offer(WebSocketRequestBuilder.sucessful()); embedder.offer(new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "path")); assertEquals(SWITCHING_PROTOCOLS, responseInterceptor.getHttpResponse().getStatus()); assertEquals(FORBIDDEN, responseInterceptor.getHttpResponse().getStatus()); } @Test public void testHttpUpgradeRequestInvalidUpgradeHeader() { DecoderEmbedder embedder = decoderEmbedder(); HttpRequest invalidUpgradeRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1) .method(HttpMethod.GET) .uri("/test") .connection("Upgrade") .version00() .upgrade("BogusSocket") .build(); try { embedder.offer(invalidUpgradeRequest); } catch (Exception e) { assertWebSocketHandshakeException(e); } } @Test public void testHttpUpgradeRequestMissingWSKeyHeader() { DecoderEmbedder embedder = decoderEmbedder(); HttpRequest missingWSKeyRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1) .method(HttpMethod.GET) .uri("/test") .key(null) .connection("Upgrade") .upgrade(WEBSOCKET.toLowerCase()) .version13() .build(); try { embedder.offer(missingWSKeyRequest); } catch (Exception e) { assertWebSocketHandshakeException(e); } } private static void assertWebSocketHandshakeException(Exception e) { assertTrue(e instanceof CodecEmbedderException); assertTrue(e.getCause() instanceof WebSocketHandshakeException); } @Test public void testHandleTextFrame() { CustomTextFrameHandler customTextFrameHandler = new CustomTextFrameHandler(); DecoderEmbedder embedder = decoderEmbedder(customTextFrameHandler); embedder.offer(WebSocketRequestBuilder.sucessful()); embedder.offer(new TextWebSocketFrame("payload")); assertEquals("processed: payload", customTextFrameHandler.getContent()); } private static DecoderEmbedder decoderEmbedder(SimpleChannelHandler handler) { DecoderEmbedder decoder = decoderEmbedder(); decoder.getPipeline().addFirst("someHandler", handler); return decoder; } private static DecoderEmbedder decoderEmbedder() { DecoderEmbedder decoder = new DecoderEmbedder( new HttpRequestDecoder(), new WebSocketServerProtocolHandler("path")); return decoder; } private static class CustomTextFrameHandler extends SimpleChannelHandler { private String content; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof TextWebSocketFrame) { TextWebSocketFrame frame = (TextWebSocketFrame) e.getMessage(); content = "processed: " + frame.getText(); } } public String getContent() { return content; } } private static class HttpResponseInterceptor extends HttpResponseEncoder { private final Queue responses = new LinkedList(); @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { responses.add((HttpResponse) msg); return super.encode(ctx, channel, msg); } public HttpResponse getHttpResponse() { return responses.poll(); } } } WebSocketUtilTest.java000066400000000000000000000037661225554127700346450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/http/websocketx/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.jboss.netty.handler.codec.http.websocketx; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Test; import java.nio.charset.Charset; import static org.junit.Assert.*; public class WebSocketUtilTest { private final static Charset UTF_8 = Charset.forName("UTF-8"); @Test public void testMd5() { byte[] bytes1 = "hello, world".getBytes(UTF_8); ChannelBuffer buf1 = ChannelBuffers.wrappedBuffer(bytes1, 0, bytes1.length); byte[] bytes2 = " hello, world".getBytes(UTF_8); ChannelBuffer buf2 = ChannelBuffers.wrappedBuffer(bytes2, 3, bytes2.length - 3); assertEquals(buf1, buf2); ChannelBuffer digest1 = WebSocketUtil.md5(buf1); ChannelBuffer digest2 = WebSocketUtil.md5(buf2); assertEquals(digest1, digest2); } @Test public void testSha1() { byte[] bytes1 = "hello, world".getBytes(UTF_8); ChannelBuffer buf1 = ChannelBuffers.wrappedBuffer(bytes1, 0, bytes1.length); byte[] bytes2 = " hello, world".getBytes(UTF_8); ChannelBuffer buf2 = ChannelBuffers.wrappedBuffer(bytes2, 3, bytes2.length - 3); assertEquals(buf1, buf2); ChannelBuffer digest1 = WebSocketUtil.sha1(buf1); ChannelBuffer digest2 = WebSocketUtil.sha1(buf2); assertEquals(digest1, digest2); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/000077500000000000000000000000001225554127700276255ustar00rootroot00000000000000AbstractCompatibleMarshallingDecoderTest.java000066400000000000000000000117321225554127700404700ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.Marshaller; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; import static org.junit.Assert.*; public abstract class AbstractCompatibleMarshallingDecoderTest { @SuppressWarnings("RedundantStringConstructorCall") private final String testObject = new String("test"); @Test public void testSimpleUnmarshalling() throws IOException { MarshallerFactory marshallerFactory = createMarshallerFactory(); MarshallingConfiguration configuration = createMarshallingConfig(); DecoderEmbedder decoder = new DecoderEmbedder(createDecoder(Integer.MAX_VALUE)); ByteArrayOutputStream bout = new ByteArrayOutputStream(); Marshaller marshaller = marshallerFactory.createMarshaller(configuration); marshaller.start(Marshalling.createByteOutput(bout)); marshaller.writeObject(testObject); marshaller.finish(); marshaller.close(); byte[] testBytes = bout.toByteArray(); decoder.offer(input(testBytes)); assertTrue(decoder.finish()); String unmarshalled = (String) decoder.poll(); assertEquals(testObject, unmarshalled); assertNull(decoder.poll()); } protected ChannelBuffer input(byte[] input) { return ChannelBuffers.wrappedBuffer(input); } @Test public void testFragmentedUnmarshalling() throws IOException { MarshallerFactory marshallerFactory = createMarshallerFactory(); MarshallingConfiguration configuration = createMarshallingConfig(); DecoderEmbedder decoder = new DecoderEmbedder(createDecoder(Integer.MAX_VALUE)); ByteArrayOutputStream bout = new ByteArrayOutputStream(); Marshaller marshaller = marshallerFactory.createMarshaller(configuration); marshaller.start(Marshalling.createByteOutput(bout)); marshaller.writeObject(testObject); marshaller.finish(); marshaller.close(); byte[] testBytes = bout.toByteArray(); ChannelBuffer buffer = input(testBytes); ChannelBuffer slice = buffer.readSlice(2); decoder.offer(slice); decoder.offer(buffer); assertTrue(decoder.finish()); String unmarshalled = (String) decoder.poll(); assertEquals(testObject, unmarshalled); assertNull(decoder.poll()); } @Test public void testTooBigObject() throws IOException { MarshallerFactory marshallerFactory = createMarshallerFactory(); MarshallingConfiguration configuration = createMarshallingConfig(); ChannelUpstreamHandler mDecoder = createDecoder(4); DecoderEmbedder decoder = new DecoderEmbedder(mDecoder); ByteArrayOutputStream bout = new ByteArrayOutputStream(); Marshaller marshaller = marshallerFactory.createMarshaller(configuration); marshaller.start(Marshalling.createByteOutput(bout)); marshaller.writeObject(testObject); marshaller.finish(); marshaller.close(); byte[] testBytes = bout.toByteArray(); try { decoder.offer(input(testBytes)); fail(); } catch (CodecEmbedderException e) { assertEquals(TooLongFrameException.class, e.getCause().getClass()); } } protected ChannelUpstreamHandler createDecoder(int maxObjectSize) { return new CompatibleMarshallingDecoder(createProvider(createMarshallerFactory(), createMarshallingConfig()), maxObjectSize); } protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new DefaultUnmarshallerProvider(factory, config); } protected abstract MarshallerFactory createMarshallerFactory(); protected abstract MarshallingConfiguration createMarshallingConfig(); } AbstractCompatibleMarshallingEncoderTest.java000066400000000000000000000052531225554127700405030ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; import org.jboss.marshalling.Unmarshaller; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.junit.Test; import java.io.IOException; import static org.junit.Assert.*; public abstract class AbstractCompatibleMarshallingEncoderTest { @Test public void testMarshalling() throws IOException, ClassNotFoundException { @SuppressWarnings("RedundantStringConstructorCall") String testObject = new String("test"); final MarshallerFactory marshallerFactory = createMarshallerFactory(); final MarshallingConfiguration configuration = createMarshallingConfig(); EncoderEmbedder encoder = new EncoderEmbedder(createEncoder()); encoder.offer(testObject); assertTrue(encoder.finish()); ChannelBuffer buffer = encoder.poll(); Unmarshaller unmarshaller = marshallerFactory.createUnmarshaller(configuration); unmarshaller.start(Marshalling.createByteInput(truncate(buffer).toByteBuffer())); String read = (String) unmarshaller.readObject(); assertEquals(testObject, read); assertEquals(-1, unmarshaller.read()); assertNull(encoder.poll()); unmarshaller.finish(); unmarshaller.close(); } protected ChannelBuffer truncate(ChannelBuffer buf) { return buf; } protected ChannelDownstreamHandler createEncoder() { return new CompatibleMarshallingEncoder(createProvider()); } protected MarshallerProvider createProvider() { return new DefaultMarshallerProvider(createMarshallerFactory(), createMarshallingConfig()); } protected abstract MarshallerFactory createMarshallerFactory(); protected abstract MarshallingConfiguration createMarshallingConfig(); } RiverCompatibleMarshallingDecoderTest.java000066400000000000000000000025211225554127700400100ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; public class RiverCompatibleMarshallingDecoderTest extends AbstractCompatibleMarshallingDecoderTest { @Override protected MarshallerFactory createMarshallerFactory() { return Marshalling.getProvidedMarshallerFactory("river"); } @Override protected MarshallingConfiguration createMarshallingConfig() { // Create a configuration final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(3); return configuration; } } RiverCompatibleMarshallingEncoderTest.java000066400000000000000000000025221225554127700400230ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; public class RiverCompatibleMarshallingEncoderTest extends AbstractCompatibleMarshallingEncoderTest { @Override protected MarshallerFactory createMarshallerFactory() { return Marshalling.getProvidedMarshallerFactory("river"); } @Override protected MarshallingConfiguration createMarshallingConfig() { // Create a configuration final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(3); return configuration; } } RiverContextBoundCompatibleMarshallingDecoderTest.java000066400000000000000000000021251225554127700423450ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class RiverContextBoundCompatibleMarshallingDecoderTest extends RiverCompatibleMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ContextBoundUnmarshallerProvider(factory, config); } } RiverContextBoundMarshallingDecoderTest.java000066400000000000000000000021011225554127700403370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class RiverContextBoundMarshallingDecoderTest extends RiverMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ContextBoundUnmarshallerProvider(factory, config); } } RiverMarshallingDecoderTest.java000066400000000000000000000025711225554127700360150ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelUpstreamHandler; public class RiverMarshallingDecoderTest extends RiverCompatibleMarshallingDecoderTest { @Override protected ChannelBuffer input(byte[] input) { ChannelBuffer length = ChannelBuffers.buffer(4); length.writeInt(input.length); return ChannelBuffers.wrappedBuffer(length, ChannelBuffers.wrappedBuffer(input)); } @Override protected ChannelUpstreamHandler createDecoder(int maxObjectSize) { return new MarshallingDecoder(createProvider(createMarshallerFactory(), createMarshallingConfig()), maxObjectSize); } } RiverMarshallingEncoderTest.java000066400000000000000000000021631225554127700360240ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelDownstreamHandler; public class RiverMarshallingEncoderTest extends RiverCompatibleMarshallingEncoderTest { @Override protected ChannelBuffer truncate(ChannelBuffer buf) { buf.readInt(); return buf; } @Override protected ChannelDownstreamHandler createEncoder() { return new MarshallingEncoder(createProvider()); } } RiverThreadLocalCompatibleMarshallingDecoderTest.java000066400000000000000000000021231225554127700421110ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class RiverThreadLocalCompatibleMarshallingDecoderTest extends RiverCompatibleMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ThreadLocalUnmarshallerProvider(factory, config); } } RiverThreadLocalCompatibleMarshallingEncoderTest.java000066400000000000000000000017211225554127700421260ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; public class RiverThreadLocalCompatibleMarshallingEncoderTest extends RiverCompatibleMarshallingEncoderTest { @Override protected MarshallerProvider createProvider() { return new ThreadLocalMarshallerProvider(createMarshallerFactory(), createMarshallingConfig()); } } RiverThreadLocalMarshallingDecoderTest.java000066400000000000000000000020771225554127700401210ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class RiverThreadLocalMarshallingDecoderTest extends RiverMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ThreadLocalUnmarshallerProvider(factory, config); } } RiverThreadLocalMarshallingEncoderTest.java000066400000000000000000000016751225554127700401360ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; public class RiverThreadLocalMarshallingEncoderTest extends RiverMarshallingEncoderTest { @Override protected MarshallerProvider createProvider() { return new ThreadLocalMarshallerProvider(createMarshallerFactory(), createMarshallingConfig()); } } SerialCompatibleMarshallingDecoderTest.java000066400000000000000000000025231225554127700401420ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; public class SerialCompatibleMarshallingDecoderTest extends AbstractCompatibleMarshallingDecoderTest { @Override protected MarshallerFactory createMarshallerFactory() { return Marshalling.getProvidedMarshallerFactory("serial"); } @Override protected MarshallingConfiguration createMarshallingConfig() { // Create a configuration final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(5); return configuration; } } SerialCompatibleMarshallingEncoderTest.java000066400000000000000000000025241225554127700401550ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; public class SerialCompatibleMarshallingEncoderTest extends AbstractCompatibleMarshallingEncoderTest { @Override protected MarshallerFactory createMarshallerFactory() { return Marshalling.getProvidedMarshallerFactory("serial"); } @Override protected MarshallingConfiguration createMarshallingConfig() { // Create a configuration final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(5); return configuration; } } SerialContextBoundCompatibleMarshallingDecoderTest.java000066400000000000000000000021271225554127700424770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class SerialContextBoundCompatibleMarshallingDecoderTest extends SerialCompatibleMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ContextBoundUnmarshallerProvider(factory, config); } } SerialContextBoundMarshallingDecoderTest.java000066400000000000000000000021031225554127700404710ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class SerialContextBoundMarshallingDecoderTest extends SerialMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ContextBoundUnmarshallerProvider(factory, config); } } SerialMarshallingDecoderTest.java000066400000000000000000000025721225554127700361460ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelUpstreamHandler; public class SerialMarshallingDecoderTest extends SerialCompatibleMarshallingDecoderTest { @Override protected ChannelBuffer input(byte[] input) { ChannelBuffer length = ChannelBuffers.buffer(4); length.writeInt(input.length); return ChannelBuffers.wrappedBuffer(length, ChannelBuffers.wrappedBuffer(input)); } @Override protected ChannelUpstreamHandler createDecoder(int maxObjectSize) { return new MarshallingDecoder(createProvider(createMarshallerFactory(), createMarshallingConfig()), maxObjectSize); } } SerialMarshallingEncoderTest.java000066400000000000000000000021641225554127700361550ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelDownstreamHandler; public class SerialMarshallingEncoderTest extends SerialCompatibleMarshallingEncoderTest{ @Override protected ChannelBuffer truncate(ChannelBuffer buf) { buf.readInt(); return buf; } @Override protected ChannelDownstreamHandler createEncoder() { return new MarshallingEncoder(createProvider()); } } SerialThreadLocalCompatibleMarshallingDecoderTest.java000066400000000000000000000021251225554127700422430ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class SerialThreadLocalCompatibleMarshallingDecoderTest extends SerialCompatibleMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ThreadLocalUnmarshallerProvider(factory, config); } } SerialThreadLocalCompatibleMarshallingEncoderTest.java000066400000000000000000000017231225554127700422600ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; public class SerialThreadLocalCompatibleMarshallingEncoderTest extends SerialCompatibleMarshallingEncoderTest { @Override protected MarshallerProvider createProvider() { return new ThreadLocalMarshallerProvider(createMarshallerFactory(), createMarshallingConfig()); } } SerialThreadLocalMarshallingDecoderTest.java000066400000000000000000000021011225554127700402350ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.MarshallingConfiguration; public class SerialThreadLocalMarshallingDecoderTest extends SerialMarshallingDecoderTest { @Override protected UnmarshallerProvider createProvider(MarshallerFactory factory, MarshallingConfiguration config) { return new ThreadLocalUnmarshallerProvider(factory, config); } } SerialThreadLocalMarshallingEncoderTest.java000066400000000000000000000016771225554127700402700ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/marshalling/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.marshalling; public class SerialThreadLocalMarshallingEncoderTest extends SerialMarshallingEncoderTest { @Override protected MarshallerProvider createProvider() { return new ThreadLocalMarshallerProvider(createMarshallerFactory(), createMarshallingConfig()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/protobuf/000077500000000000000000000000001225554127700271645ustar00rootroot00000000000000ProtobufVarint32FrameDecoderTest.java000066400000000000000000000043401225554127700362030ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/protobuf/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import static org.hamcrest.core.Is.*; import static org.hamcrest.core.IsNull.*; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.junit.Before; import org.junit.Test; public class ProtobufVarint32FrameDecoderTest { private DecoderEmbedder embedder; @Before public void setUp() { embedder = new DecoderEmbedder( new ProtobufVarint32FrameDecoder()); } @Test public void testTinyDecode() { byte[] b = { 4, 1, 1, 1, 1 }; embedder.offer(wrappedBuffer(b, 0, 1)); assertThat(embedder.poll(), is(nullValue())); embedder.offer(wrappedBuffer(b, 1, 2)); assertThat(embedder.poll(), is(nullValue())); embedder.offer(wrappedBuffer(b, 3, b.length - 3)); assertThat(embedder.poll(), is(wrappedBuffer(new byte[] { 1, 1, 1, 1 }))); } @Test public void testRegularDecode() { byte[] b = new byte[2048]; for (int i = 2; i < 2048; i ++) { b[i] = 1; } b[0] = -2; b[1] = 15; embedder.offer(wrappedBuffer(b, 0, 127)); assertThat(embedder.poll(), is(nullValue())); embedder.offer(wrappedBuffer(b, 127, 600)); assertThat(embedder.poll(), is(nullValue())); embedder.offer(wrappedBuffer(b, 727, b.length - 727)); assertThat(embedder.poll(), is(wrappedBuffer(b, 2, b.length - 2))); } } ProtobufVarint32LengthFieldPrependerTest.java000066400000000000000000000033521225554127700377170ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/protobuf/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import static org.hamcrest.core.Is.*; import static org.jboss.netty.buffer.ChannelBuffers.*; import static org.junit.Assert.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.junit.Before; import org.junit.Test; public class ProtobufVarint32LengthFieldPrependerTest { private EncoderEmbedder embedder; @Before public void setUp() { embedder = new EncoderEmbedder( new ProtobufVarint32LengthFieldPrepender()); } @Test public void testTinyEncode() { byte[] b = { 4, 1, 1, 1, 1 }; embedder.offer(wrappedBuffer(b, 1, b.length - 1)); assertThat(embedder.poll(), is(wrappedBuffer(b))); } @Test public void testRegularDecode() { byte[] b = new byte[2048]; for (int i = 2; i < 2048; i ++) { b[i] = 1; } b[0] = -2; b[1] = 15; embedder.offer(wrappedBuffer(b, 2, b.length - 2)); assertThat(embedder.poll(), is(wrappedBuffer(b))); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/replay/000077500000000000000000000000001225554127700266205ustar00rootroot00000000000000ReplayingDecoderBufferTest.java000066400000000000000000000050701225554127700346200ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/replay/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; public class ReplayingDecoderBufferTest { /** * See https://github.com/netty/netty/issues/445 */ @Test public void testGetUnsignedByte() { ReplayingDecoderBuffer buffer = new ReplayingDecoderBuffer(new ReplayDecoderImpl()); boolean error; int i = 0; try { for (;;) { buffer.getUnsignedByte(i); i++; } } catch (ReplayError e) { error = true; } assertTrue(error); assertEquals(10, i); } /** * See https://github.com/netty/netty/issues/445 */ @Test public void testGetByte() { ReplayingDecoderBuffer buffer = new ReplayingDecoderBuffer(new ReplayDecoderImpl()); boolean error; int i = 0; try { for (;;) { buffer.getByte(i); i++; } } catch (ReplayError e) { error = true; } assertTrue(error); assertEquals(10, i); } private static class ReplayDecoderImpl extends ReplayingDecoder { private final ChannelBuffer internal = ChannelBuffers.copiedBuffer("TestBuffer", CharsetUtil.ISO_8859_1); @Override protected ChannelBuffer internalBuffer() { return internal; } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { throw new UnsupportedOperationException(); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/replay/ReplayingDecoderTest.java000066400000000000000000000076671225554127700335630ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.replay; import static org.junit.Assert.*; import java.util.concurrent.atomic.AtomicBoolean; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferIndexFinder; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; public class ReplayingDecoderTest { @Test public void testLineProtocol() { DecoderEmbedder e = new DecoderEmbedder( new LineDecoder()); // Ordinary input e.offer(ChannelBuffers.wrappedBuffer(new byte[] { 'A' })); assertNull(e.poll()); e.offer(ChannelBuffers.wrappedBuffer(new byte[] { 'B' })); assertNull(e.poll()); e.offer(ChannelBuffers.wrappedBuffer(new byte[] { 'C' })); assertNull(e.poll()); e.offer(ChannelBuffers.wrappedBuffer(new byte[] { '\n' })); assertEquals(ChannelBuffers.wrappedBuffer(new byte[] { 'A', 'B', 'C' }), e.poll()); // Truncated input e.offer(ChannelBuffers.wrappedBuffer(new byte[] { 'A' })); assertNull(e.poll()); e.finish(); assertNull(e.poll()); } @Test public void testAssertFailure() { final AtomicBoolean fail = new AtomicBoolean(true); DecoderEmbedder e = new DecoderEmbedder( new ReplayingDecoder() { @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { if (fail.get()) { for (;;) { try { buffer.readByte(); } catch (ReplayError er) { break; } } fail.set(false); throw new Exception(); } buffer.readByte(); return new Object(); } }); try { e.offer(ChannelBuffers.copiedBuffer("TESTME!!!!", CharsetUtil.US_ASCII)); fail(); } catch (CodecEmbedderException ex) { // expected } // this will trigger an assert error when asserts are enabled via the -ea // jvm switch. This is the default when run via the maven sunfire plugin e.offer(ChannelBuffers.copiedBuffer("TESTME!!!!", CharsetUtil.US_ASCII)); e.finish(); } private static final class LineDecoder extends ReplayingDecoder { LineDecoder() { } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { ChannelBuffer msg = buffer.readBytes( buffer.bytesBefore(ChannelBufferIndexFinder.LF)); buffer.skipBytes(1); return msg; } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/000077500000000000000000000000001225554127700302015ustar00rootroot00000000000000AbstractSocketCompatibleObjectStreamEchoTest.java000066400000000000000000000134371225554127700416530ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; public abstract class AbstractSocketCompatibleObjectStreamEchoTest { static final Random random = new Random(); static final String[] data = new String[1024]; static { for (int i = 0; i < data.length; i ++) { int eLen = random.nextInt(512); char[] e = new char[eLen]; for (int j = 0; j < eLen; j ++) { e[j] = (char) ('a' + random.nextInt(26)); } data[i] = new String(e); } } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test @SuppressWarnings("deprecation") public void testCompatibleObjectEcho() throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(Executors.newCachedThreadPool())); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); EchoHandler sh = new EchoHandler(); EchoHandler ch = new EchoHandler(); sb.getPipeline().addLast("decoder", new CompatibleObjectDecoder()); sb.getPipeline().addLast("encoder", new CompatibleObjectEncoder()); sb.getPipeline().addLast("handler", sh); cb.getPipeline().addLast("decoder", new CompatibleObjectDecoder()); cb.getPipeline().addLast("encoder", new CompatibleObjectEncoder()); cb.getPipeline().addLast("handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); for (String element : data) { cc.write(element); } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; EchoHandler() { } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String m = (String) e.getMessage(); assertEquals(data[counter], m); if (channel.getParent() != null) { channel.write(m); } counter ++; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (exception.compareAndSet(null, e.getCause())) { e.getChannel().close(); } } } } AbstractSocketObjectStreamEchoTest.java000066400000000000000000000135251225554127700376510ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; public abstract class AbstractSocketObjectStreamEchoTest { static final Random random = new Random(); static final String[] data = new String[1024]; static { for (int i = 0; i < data.length; i ++) { int eLen = random.nextInt(512); char[] e = new char[eLen]; for (int j = 0; j < eLen; j ++) { e[j] = (char) ('a' + random.nextInt(26)); } data[i] = new String(e); } } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testObjectEcho() throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(Executors.newCachedThreadPool())); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); EchoHandler sh = new EchoHandler(); EchoHandler ch = new EchoHandler(); sb.getPipeline().addLast("decoder", new ObjectDecoder( ClassResolvers.cacheDisabled(String.class.getClassLoader()))); sb.getPipeline().addLast("encoder", new ObjectEncoder()); sb.getPipeline().addLast("handler", sh); cb.getPipeline().addLast("decoder", new ObjectDecoder( ClassResolvers.cacheDisabled(String.class.getClassLoader()))); cb.getPipeline().addLast("encoder", new ObjectEncoder()); cb.getPipeline().addLast("handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); for (String element : data) { cc.write(element); } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; EchoHandler() { } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String m = (String) e.getMessage(); assertEquals(data[counter], m); if (channel.getParent() != null) { channel.write(m); } counter ++; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (exception.compareAndSet(null, e.getCause())) { e.getChannel().close(); } } } } CompactObjectSerializationTest.java000066400000000000000000000025311225554127700371010ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.List; import org.junit.Assert; import org.junit.Test; public class CompactObjectSerializationTest { @Test public void testInterfaceSerialization() throws Exception { PipedOutputStream pipeOut = new PipedOutputStream(); PipedInputStream pipeIn = new PipedInputStream(pipeOut); CompactObjectOutputStream out = new CompactObjectOutputStream(pipeOut); CompactObjectInputStream in = new CompactObjectInputStream(pipeIn, ClassResolvers.cacheDisabled(null)); out.writeObject(List.class); Assert.assertSame(List.class, in.readObject()); } } NioNioSocketCompatibleObjectStreamEchoTest.java000066400000000000000000000025421225554127700412760ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } NioNioSocketObjectStreamEchoTest.java000066400000000000000000000025161225554127700372770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } NioOioSocketCompatibleObjectStreamEchoTest.java000066400000000000000000000025421225554127700412770ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } NioOioSocketObjectStreamEchoTest.java000066400000000000000000000025161225554127700373000ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } OioNioSocketCompatibleObjectStreamEchoTest.java000066400000000000000000000025301225554127700412740ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; public class OioNioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } OioNioSocketObjectStreamEchoTest.java000066400000000000000000000025141225554127700372760ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; /** */ public class OioNioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } OioOioSocketCompatibleObjectStreamEchoTest.java000066400000000000000000000025301225554127700412750ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } OioOioSocketObjectStreamEchoTest.java000066400000000000000000000025041225554127700372760ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } SwitchableInputStreamTest.java000066400000000000000000000027001225554127700361050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/serialization/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.serialization; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.io.InputStream; import org.junit.Test; public class SwitchableInputStreamTest { @Test public void testSwitchStream() throws Exception { SwitchableInputStream sin = new SwitchableInputStream(); InputStream in1 = createStrictMock(InputStream.class); InputStream in2 = createStrictMock(InputStream.class); expect(in1.read()).andReturn(1); replay(in1, in2); sin.switchStream(in1); assertEquals(1, sin.read()); verify(in1, in2); reset(in1, in2); expect(in2.read()).andReturn(2); replay(in1, in2); sin.switchStream(in2); assertEquals(2, sin.read()); verify(in1, in2); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/000077500000000000000000000000001225554127700264465ustar00rootroot00000000000000SocksAuthRequestDecoderTest.java000066400000000000000000000027061225554127700346420ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.junit.Test; import static org.junit.Assert.*; public class SocksAuthRequestDecoderTest { @Test public void testAuthRequestDecoder() throws Exception{ String username = "test"; String password = "test"; SocksAuthRequest msg = new SocksAuthRequest(username, password); SocksAuthRequestDecoder decoder = new SocksAuthRequestDecoder(); DecoderEmbedder embedder = new DecoderEmbedder(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); msg = embedder.poll(); assertEquals(msg.getUsername(), username); assertEquals(msg.getUsername(), password); assertNull(embedder.poll()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksAuthRequestTest.java000066400000000000000000000064601225554127700334340ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.junit.Test; import static org.junit.Assert.assertTrue; public class SocksAuthRequestTest { @Test public void testConstructorParamsAreNotNull() { try { new SocksAuthRequest(null, ""); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } try { new SocksAuthRequest("", null); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } } @Test public void testUsernameOrPasswordIsNotAscii() { try { new SocksAuthRequest("παράδειγμα.δοκιμή", "password"); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { new SocksAuthRequest("username", "παράδειγμα.δοκιμή"); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } @Test public void testUsernameOrPasswordLengthIsLessThan255Chars() { try { new SocksAuthRequest( "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword", "password"); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { new SocksAuthRequest("password", "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpassword"); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } } SocksAuthResponseDecoderTest.java000066400000000000000000000037111225554127700350050ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.junit.Test; import static org.junit.Assert.*; public class SocksAuthResponseDecoderTest { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksAuthResponseDecoderTest.class); private static void testSocksAuthResponseDecoderWithDifferentParams(SocksMessage.AuthStatus authStatus) throws Exception{ logger.debug("Testing SocksAuthResponseDecoder with authStatus: "+ authStatus); SocksAuthResponse msg = new SocksAuthResponse(authStatus); SocksAuthResponseDecoder decoder = new SocksAuthResponseDecoder(); DecoderEmbedder embedder = new DecoderEmbedder(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); msg = embedder.poll(); assertSame(msg.getAuthStatus(), authStatus); assertNull(embedder.poll()); } @Test public void testSocksCmdResponseDecoder() throws Exception { for (SocksMessage.AuthStatus authStatus: SocksMessage.AuthStatus.values()) { testSocksAuthResponseDecoderWithDifferentParams(authStatus); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksAuthResponseTest.java000066400000000000000000000017631225554127700336030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.junit.Test; import static org.junit.Assert.assertTrue; public class SocksAuthResponseTest { @Test public void testConstructorParamsAreNotNull() { try { new SocksAuthResponse(null); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } } } SocksCmdRequestDecoderTest.java000066400000000000000000000111401225554127700344340ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.junit.Test; import sun.net.util.IPAddressUtil; import static org.junit.Assert.*; public class SocksCmdRequestDecoderTest { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksCmdRequestDecoderTest.class); private static void testSocksCmdRequestDecoderWithDifferentParams(SocksMessage.CmdType cmdType, SocksMessage.AddressType addressType, String host, int port) throws Exception { logger.debug("Testing cmdType: " + cmdType + " addressType: " + addressType + " host: " + host + " port: " + port); SocksCmdRequest msg = new SocksCmdRequest(cmdType, addressType, host, port); SocksCmdRequestDecoder decoder = new SocksCmdRequestDecoder(); DecoderEmbedder embedder = new DecoderEmbedder(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); if (msg.getAddressType() == SocksMessage.AddressType.UNKNOWN) { assertTrue(embedder.poll() instanceof UnknownSocksRequest); } else { msg = (SocksCmdRequest) embedder.poll(); assertSame(msg.getCmdType(), cmdType); assertSame(msg.getAddressType(), addressType); assertEquals(msg.getHost(), host); assertEquals(msg.getPort(), port); } assertNull(embedder.poll()); } @Test public void testCmdRequestDecoderIPv4() throws Exception{ String[] hosts = { "127.0.0.1" }; int[] ports = {0, 32769, 65535 }; for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) { for (String host : hosts) { for (int port : ports) { testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.IPv4, host, port); } } } } @Test public void testCmdRequestDecoderIPv6() throws Exception{ String[] hosts = { SocksCommonUtils.ipv6toStr(IPAddressUtil.textToNumericFormatV6("::1")) }; int[] ports = {0, 32769, 65535}; for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) { for (String host : hosts) { for (int port : ports) { testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.IPv6, host, port); } } } } @Test public void testCmdRequestDecoderDomain() throws Exception{ String[] hosts = {"google.com" , "مثال.إختبار", "παράδειγμα.δοκιμή", "مثال.آزمایشی", "пример.испытание", "בײַשפּיל.טעסט", "例子.测试", "例子.測試", "उदाहरण.परीक्षा", "例え.テスト", "실례.테스트", "உதாரணம்.பரிட்சை"}; int[] ports = {0, 32769, 65535}; for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) { for (String host : hosts) { for (int port : ports) { testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.DOMAIN, host, port); } } } } @Test public void testCmdRequestDecoderUnknown() throws Exception{ String host = "google.com"; int port = 80; for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) { testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.UNKNOWN, host, port); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksCmdRequestTest.java000066400000000000000000000067641225554127700332450ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.junit.Test; import static org.junit.Assert.assertTrue; public class SocksCmdRequestTest { @Test public void testConstructorParamsAreNotNull(){ try { new SocksCmdRequest(null, SocksMessage.AddressType.UNKNOWN, "", 0); } catch (Exception e){ assertTrue(e instanceof NullPointerException); } try { new SocksCmdRequest(SocksMessage.CmdType.UNKNOWN, null, "", 0); } catch (Exception e){ assertTrue(e instanceof NullPointerException); } try { new SocksCmdRequest(SocksMessage.CmdType.UNKNOWN, SocksMessage.AddressType.UNKNOWN, null, 0); } catch (Exception e){ assertTrue(e instanceof NullPointerException); } } @Test public void testIPv4CorrectAddress(){ try { new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.IPv4, "54.54.1111.253", 0); } catch (Exception e){ assertTrue(e instanceof IllegalArgumentException); } } @Test public void testIPv6CorrectAddress(){ try { new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.IPv6, "xxx:xxx:xxx", 0); } catch (Exception e){ assertTrue(e instanceof IllegalArgumentException); } } @Test public void testIDNNotExceeds255CharsLimit(){ try { new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.DOMAIN, "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" + "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" + "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" + "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή", 0); } catch (Exception e){ assertTrue(e instanceof IllegalArgumentException); } } @Test public void testValidPortRange(){ try { new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.DOMAIN, "παράδειγμα.δοκιμήπαράδει", -1); } catch (Exception e){ assertTrue(e instanceof IllegalArgumentException); } try { new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.DOMAIN, "παράδειγμα.δοκιμήπαράδει", 65536); } catch (Exception e){ assertTrue(e instanceof IllegalArgumentException); } } } SocksCmdResponseDecoderTest.java000066400000000000000000000044441225554127700346130ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.junit.Test; import static org.junit.Assert.*; public class SocksCmdResponseDecoderTest { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksCmdResponseDecoderTest.class); private static void testSocksCmdResponseDecoderWithDifferentParams(SocksMessage.CmdStatus cmdStatus, SocksMessage.AddressType addressType) throws Exception { logger.debug("Testing cmdStatus: " + cmdStatus + " addressType: " + addressType); SocksResponse msg = new SocksCmdResponse(cmdStatus, addressType); SocksCmdResponseDecoder decoder = new SocksCmdResponseDecoder(); DecoderEmbedder embedder = new DecoderEmbedder(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); if (addressType == SocksMessage.AddressType.UNKNOWN) { assertTrue(embedder.poll() instanceof UnknownSocksResponse); } else { msg = embedder.poll(); assertEquals(((SocksCmdResponse) msg).getCmdStatus(), cmdStatus); } assertNull(embedder.poll()); } @Test public void testSocksCmdResponseDecoder() throws Exception { for (SocksMessage.CmdStatus cmdStatus: SocksMessage.CmdStatus.values()) { for (SocksMessage.AddressType addressType: SocksMessage.AddressType.values()) { testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, addressType); } } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksCmdResponseTest.java000066400000000000000000000023211225554127700333740ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.junit.Test; import static org.junit.Assert.assertTrue; public class SocksCmdResponseTest { @Test public void testConstructorParamsAreNotNull() { try { new SocksCmdResponse(null, SocksMessage.AddressType.UNKNOWN); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } try { new SocksCmdResponse(SocksMessage.CmdStatus.UNASSIGNED, null); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksCommonTestUtils.java000066400000000000000000000025001225554127700334220ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; final class SocksCommonTestUtils { private static final int DEFAULT_ENCODER_BUFFER_SIZE = 1024; /** * A constructor to stop this class being constructed. */ private SocksCommonTestUtils() { //NOOP } public static void writeMessageIntoEmbedder(DecoderEmbedder embedder, SocksMessage msg) throws Exception { ChannelBuffer buf = ChannelBuffers.buffer(DEFAULT_ENCODER_BUFFER_SIZE); msg.encodeAsByteBuf(buf); embedder.offer(buf); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksInitRequestTest.java000066400000000000000000000017611225554127700334350ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.junit.Test; import static org.junit.Assert.assertTrue; public class SocksInitRequestTest { @Test public void testConstructorParamsAreNotNull() { try { new SocksInitRequest(null); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/socks/SocksInitResponseTest.java000066400000000000000000000017631225554127700336050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.socks; import org.junit.Test; import static org.junit.Assert.assertTrue; public class SocksInitResponseTest { @Test public void testConstructorParamsAreNotNull() { try { new SocksInitResponse(null); } catch (Exception e) { assertTrue(e instanceof NullPointerException); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/000077500000000000000000000000001225554127700263035ustar00rootroot00000000000000AbstractSocketSpdyEchoTest.java000066400000000000000000000213001225554127700342760ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.TestUtil; import org.junit.Test; public abstract class AbstractSocketSpdyEchoTest { private static final Random random = new Random(); static final int ignoredBytes = 20; private static ChannelBuffer createFrames(int version) { ChannelBuffer frames = ChannelBuffers.buffer(1174); // SPDY UNKNOWN Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(0xFFFF); frames.writeByte(0xFF); frames.writeMedium(4); frames.writeInt(random.nextInt()); // SPDY NOOP Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(5); frames.writeInt(0); // SPDY Data Frame frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); frames.writeByte(0x01); frames.writeMedium(1024); for (int i = 0; i < 256; i ++) { frames.writeInt(random.nextInt()); } // SPDY SYN_STREAM Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(1); frames.writeByte(0x03); frames.writeMedium(10); frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); frames.writeInt(random.nextInt() & 0x7FFFFFFF); frames.writeShort(0x8000); // SPDY SYN_REPLY Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(2); frames.writeByte(0x01); frames.writeMedium(4); frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); // SPDY RST_STREAM Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(3); frames.writeInt(8); frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); frames.writeInt(random.nextInt() | 0x01); // SPDY SETTINGS Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(4); frames.writeByte(0x01); frames.writeMedium(12); frames.writeInt(1); frames.writeByte(0x03); frames.writeMedium(random.nextInt()); frames.writeInt(random.nextInt()); // SPDY PING Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(6); frames.writeInt(4); frames.writeInt(random.nextInt()); // SPDY GOAWAY Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(7); frames.writeInt(8); frames.writeInt(random.nextInt() & 0x7FFFFFFF); frames.writeInt(random.nextInt() | 0x01); // SPDY HEADERS Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(8); frames.writeByte(0x01); frames.writeMedium(4); frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); // SPDY WINDOW_UPDATE Frame frames.writeByte(0x80); frames.writeByte(version); frames.writeShort(9); frames.writeInt(8); frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); frames.writeInt(random.nextInt() & 0x7FFFFFFF | 0x01); return frames; } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testSpdyEcho() throws Throwable { testSpdyEcho(SpdyVersion.SPDY_3); testSpdyEcho(SpdyVersion.SPDY_3_1); } private void testSpdyEcho(SpdyVersion version) throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(Executors.newCachedThreadPool())); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); ChannelBuffer frames = createFrames(version.getVersion()); EchoHandler sh = new EchoHandler(frames, true); EchoHandler ch = new EchoHandler(frames, false); sb.getPipeline().addLast("decoder", new SpdyFrameDecoder(version)); sb.getPipeline().addLast("encoder", new SpdyFrameEncoder(version)); sb.getPipeline().addLast("handler", sh); cb.getPipeline().addLast("handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); cc.write(frames); while (ch.counter < frames.writerIndex() - ignoredBytes) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); final ChannelBuffer frames; volatile int counter; final boolean server; EchoHandler(ChannelBuffer frames, boolean server) { this.frames = frames; this.server = server; } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (server) { Channels.write(channel, e.getMessage(), e.getRemoteAddress()); } else { ChannelBuffer m = (ChannelBuffer) e.getMessage(); byte[] actual = new byte[m.readableBytes()]; m.getBytes(0, actual); int lastIdx = counter; for (int i = 0; i < actual.length; i ++) { assertEquals(frames.getByte(ignoredBytes + i + lastIdx), actual[i]); } counter += actual.length; } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (exception.compareAndSet(null, e.getCause())) { e.getChannel().close(); } } } } NioNioSocketSpdyEchoTest.java000066400000000000000000000024651225554127700337410ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } NioOioSocketSpdyEchoTest.java000066400000000000000000000024651225554127700337420ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } OioNioSocketSpdyEchoTest.java000066400000000000000000000024531225554127700337370ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; public class OioNioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } OioOioSocketSpdyEchoTest.java000066400000000000000000000024531225554127700337400ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/SpdyFrameDecoderTest.java000066400000000000000000000134411225554127700331710ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.util.TestUtil; import org.junit.Test; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import static org.junit.Assert.*; public class SpdyFrameDecoderTest { @Test public void testTooLargeHeaderNameOnSynStreamRequest() throws Exception { testTooLargeHeaderNameOnSynStreamRequest(SpdyVersion.SPDY_3); testTooLargeHeaderNameOnSynStreamRequest(SpdyVersion.SPDY_3_1); } private void testTooLargeHeaderNameOnSynStreamRequest(SpdyVersion spdyVersion) throws Exception { List headerSizes = Arrays.asList(90, 900); for (int maxHeaderSize : headerSizes) { // 90 catches the header name, 900 the value SpdyHeadersFrame frame = new DefaultSpdySynStreamFrame(1, 0, (byte) 0); addHeader(frame, 100, 1000); CaptureHandler captureHandler = new CaptureHandler(); ServerBootstrap sb = new ServerBootstrap( newServerSocketChannelFactory(Executors.newCachedThreadPool())); ClientBootstrap cb = new ClientBootstrap( newClientSocketChannelFactory(Executors.newCachedThreadPool())); sb.getPipeline().addLast("decoder", new SpdyFrameDecoder(spdyVersion, 10000, maxHeaderSize)); sb.getPipeline().addLast("sessionHandler", new SpdySessionHandler(spdyVersion, true)); sb.getPipeline().addLast("handler", captureHandler); cb.getPipeline().addLast("encoder", new SpdyFrameEncoder(spdyVersion)); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); sendAndWaitForFrame(cc, frame, captureHandler); assertNotNull("version " + spdyVersion.getVersion() + ", not null message", captureHandler.message); String message = "version " + spdyVersion.getVersion() + ", should be SpdyHeadersFrame, was " + captureHandler.message.getClass(); assertTrue( message, captureHandler.message instanceof SpdyHeadersFrame); SpdyHeadersFrame writtenFrame = (SpdyHeadersFrame) captureHandler.message; assertTrue("should be truncated", writtenFrame.isTruncated()); assertFalse("should not be invalid", writtenFrame.isInvalid()); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); } } private static void sendAndWaitForFrame(Channel cc, SpdyFrame frame, CaptureHandler handler) { cc.write(frame); long theFuture = System.currentTimeMillis() + 3000; while (handler.message == null && System.currentTimeMillis() < theFuture) { try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } } private static void addHeader(SpdyHeadersFrame frame, int headerNameSize, int headerValueSize) { frame.headers().add("k", "v"); StringBuilder headerName = new StringBuilder(); for (int i = 0; i < headerNameSize; i++) { headerName.append('h'); } StringBuilder headerValue = new StringBuilder(); for (int i = 0; i < headerValueSize; i++) { headerValue.append('a'); } frame.headers().add(headerName.toString(), headerValue.toString()); } protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } private static class CaptureHandler extends SimpleChannelUpstreamHandler { public volatile Object message; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { message = e.getMessage(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); message = e.getCause(); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/spdy/SpdySessionHandlerTest.java000066400000000000000000000402371225554127700335750ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.spdy; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.junit.Test; import java.util.List; import java.util.Map; import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*; import static org.junit.Assert.*; public class SpdySessionHandlerTest { private static final int closeSignal = SPDY_SETTINGS_MAX_ID; private static final SpdySettingsFrame closeMessage = new DefaultSpdySettingsFrame(); static { closeMessage.setValue(closeSignal, 0); } private static void assertDataFrame(Object msg, int streamId, boolean last) { assertNotNull(msg); assertTrue(msg instanceof SpdyDataFrame); SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; assertEquals(spdyDataFrame.getStreamId(), streamId); assertEquals(spdyDataFrame.isLast(), last); } private static void assertSynReply(Object msg, int streamId, boolean last, SpdyHeaders headers) { assertNotNull(msg); assertTrue(msg instanceof SpdySynReplyFrame); assertHeaders(msg, streamId, last, headers); } private static void assertRstStream(Object msg, int streamId, SpdyStreamStatus status) { assertNotNull(msg); assertTrue(msg instanceof SpdyRstStreamFrame); SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; assertEquals(spdyRstStreamFrame.getStreamId(), streamId); assertEquals(spdyRstStreamFrame.getStatus(), status); } private static void assertPing(Object msg, int id) { assertNotNull(msg); assertTrue(msg instanceof SpdyPingFrame); SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; assertEquals(spdyPingFrame.getId(), id); } private static void assertGoAway(Object msg, int lastGoodStreamId) { assertNotNull(msg); assertTrue(msg instanceof SpdyGoAwayFrame); SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg; assertEquals(spdyGoAwayFrame.getLastGoodStreamId(), lastGoodStreamId); } private static void assertHeaders(Object msg, int streamId, boolean last, SpdyHeaders headers) { assertNotNull(msg); assertTrue(msg instanceof SpdyHeadersFrame); SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; assertEquals(spdyHeadersFrame.getStreamId(), streamId); assertEquals(spdyHeadersFrame.isLast(), last); for (String name: headers.names()) { List expectedValues = headers.getAll(name); List receivedValues = spdyHeadersFrame.headers().getAll(name); assertTrue(receivedValues.containsAll(expectedValues)); receivedValues.removeAll(expectedValues); assertTrue(receivedValues.isEmpty()); spdyHeadersFrame.headers().remove(name); } assertTrue(spdyHeadersFrame.headers().isEmpty()); } private static void testSpdySessionHandler(SpdyVersion spdyVersion, boolean server) { DecoderEmbedder sessionHandler = new DecoderEmbedder( new SpdySessionHandler(spdyVersion, server), new EchoHandler(closeSignal, server)); sessionHandler.pollAll(); int localStreamId = server ? 1 : 2; int remoteStreamId = server ? 2 : 1; SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0); spdySynStreamFrame.headers().set("Compression", "test"); SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamId); spdyDataFrame.setLast(true); // Check if session handler returns INVALID_STREAM if it receives // a data frame for a Stream-ID that is not open sessionHandler.offer(new DefaultSpdyDataFrame(localStreamId)); assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.INVALID_STREAM); assertNull(sessionHandler.peek()); // Check if session handler returns PROTOCOL_ERROR if it receives // a data frame for a Stream-ID before receiving a SYN_REPLY frame sessionHandler.offer(new DefaultSpdyDataFrame(remoteStreamId)); assertRstStream(sessionHandler.poll(), remoteStreamId, SpdyStreamStatus.PROTOCOL_ERROR); assertNull(sessionHandler.peek()); remoteStreamId += 2; // Check if session handler returns PROTOCOL_ERROR if it receives // multiple SYN_REPLY frames for the same active Stream-ID sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamId)); assertNull(sessionHandler.peek()); sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamId)); assertRstStream(sessionHandler.poll(), remoteStreamId, SpdyStreamStatus.STREAM_IN_USE); assertNull(sessionHandler.peek()); remoteStreamId += 2; // Check if frame codec correctly compresses/uncompresses headers sessionHandler.offer(spdySynStreamFrame); assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame.headers()); assertNull(sessionHandler.peek()); SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(localStreamId); spdyHeadersFrame.headers().add("HEADER","test1"); spdyHeadersFrame.headers().add("HEADER","test2"); sessionHandler.offer(spdyHeadersFrame); assertHeaders(sessionHandler.poll(), localStreamId, false, spdyHeadersFrame.headers()); assertNull(sessionHandler.peek()); localStreamId += 2; // Check if session handler closed the streams using the number // of concurrent streams and that it returns REFUSED_STREAM // if it receives a SYN_STREAM frame it does not wish to accept spdySynStreamFrame.setStreamId(localStreamId); spdySynStreamFrame.setLast(true); spdySynStreamFrame.setUnidirectional(true); sessionHandler.offer(spdySynStreamFrame); assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.REFUSED_STREAM); assertNull(sessionHandler.peek()); // Check if session handler rejects HEADERS for closed streams int testStreamId = spdyDataFrame.getStreamId(); sessionHandler.offer(spdyDataFrame); assertDataFrame(sessionHandler.poll(), testStreamId, spdyDataFrame.isLast()); assertNull(sessionHandler.peek()); spdyHeadersFrame.setStreamId(testStreamId); sessionHandler.offer(spdyHeadersFrame); assertRstStream(sessionHandler.poll(), testStreamId, SpdyStreamStatus.INVALID_STREAM); assertNull(sessionHandler.peek()); // Check if session handler drops active streams if it receives // a RST_STREAM frame for that Stream-ID sessionHandler.offer(new DefaultSpdyRstStreamFrame(remoteStreamId, 3)); assertNull(sessionHandler.peek()); remoteStreamId += 2; // Check if session handler honors UNIDIRECTIONAL streams spdySynStreamFrame.setLast(false); sessionHandler.offer(spdySynStreamFrame); assertNull(sessionHandler.peek()); spdySynStreamFrame.setUnidirectional(false); // Check if session handler returns PROTOCOL_ERROR if it receives // multiple SYN_STREAM frames for the same active Stream-ID sessionHandler.offer(spdySynStreamFrame); assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.PROTOCOL_ERROR); assertNull(sessionHandler.peek()); localStreamId += 2; // Check if session handler returns PROTOCOL_ERROR if it receives // a SYN_STREAM frame with an invalid Stream-ID spdySynStreamFrame.setStreamId(localStreamId - 1); sessionHandler.offer(spdySynStreamFrame); assertRstStream(sessionHandler.poll(), localStreamId - 1, SpdyStreamStatus.PROTOCOL_ERROR); assertNull(sessionHandler.peek()); spdySynStreamFrame.setStreamId(localStreamId); // Check if session handler returns PROTOCOL_ERROR if it receives // an invalid HEADERS frame spdyHeadersFrame.setStreamId(localStreamId); spdyHeadersFrame.setInvalid(); sessionHandler.offer(spdyHeadersFrame); assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.PROTOCOL_ERROR); assertNull(sessionHandler.peek()); sessionHandler.finish(); } @Test public void testSpdyClientSessionHandler() { testSpdySessionHandler(SpdyVersion.SPDY_3, false); testSpdySessionHandler(SpdyVersion.SPDY_3_1, false); } @Test public void testSpdyClientSessionHandlerPing() { testSpdySessionHandlerPing(SpdyVersion.SPDY_3, false); testSpdySessionHandlerPing(SpdyVersion.SPDY_3_1, false); } @Test public void testSpdyClientSessionHandlerGoAway() { testSpdySessionHandlerGoAway(SpdyVersion.SPDY_3, false); testSpdySessionHandlerGoAway(SpdyVersion.SPDY_3_1, false); } @Test public void testSpdyServerSessionHandler() { testSpdySessionHandler(SpdyVersion.SPDY_3, true); testSpdySessionHandler(SpdyVersion.SPDY_3_1, true); } @Test public void testSpdyServerSessionHandlerPing() { testSpdySessionHandlerPing(SpdyVersion.SPDY_3, true); testSpdySessionHandlerPing(SpdyVersion.SPDY_3_1, true); } @Test public void testSpdyServerSessionHandlerGoAway() { testSpdySessionHandlerGoAway(SpdyVersion.SPDY_3, true); testSpdySessionHandlerGoAway(SpdyVersion.SPDY_3_1, true); } private static void testSpdySessionHandlerPing(SpdyVersion spdyVersion, boolean server) { DecoderEmbedder sessionHandler = new DecoderEmbedder( new SpdySessionHandler(spdyVersion, server), new EchoHandler(closeSignal, server)); sessionHandler.pollAll(); int localStreamId = server ? 1 : 2; int remoteStreamId = server ? 2 : 1; SpdyPingFrame localPingFrame = new DefaultSpdyPingFrame(localStreamId); SpdyPingFrame remotePingFrame = new DefaultSpdyPingFrame(remoteStreamId); // Check if session handler returns identical local PINGs sessionHandler.offer(localPingFrame); assertPing(sessionHandler.poll(), localPingFrame.getId()); assertNull(sessionHandler.peek()); // Check if session handler ignores un-initiated remote PINGs sessionHandler.offer(remotePingFrame); assertNull(sessionHandler.peek()); sessionHandler.finish(); } private static void testSpdySessionHandlerGoAway(SpdyVersion spdyVersion, boolean server) { DecoderEmbedder sessionHandler = new DecoderEmbedder( new SpdySessionHandler(spdyVersion, server), new EchoHandler(closeSignal, server)); sessionHandler.pollAll(); int localStreamId = server ? 1 : 2; int remoteStreamId = server ? 2 : 1; SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0); spdySynStreamFrame.headers().set("Compression", "test"); SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamId); spdyDataFrame.setLast(true); // Send an initial request sessionHandler.offer(spdySynStreamFrame); assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame.headers()); assertNull(sessionHandler.peek()); sessionHandler.offer(spdyDataFrame); assertDataFrame(sessionHandler.poll(), localStreamId, true); assertNull(sessionHandler.peek()); // Check if session handler sends a GOAWAY frame when closing sessionHandler.offer(closeMessage); assertGoAway(sessionHandler.poll(), localStreamId); assertNull(sessionHandler.peek()); localStreamId += 2; // Check if session handler returns REFUSED_STREAM if it receives // SYN_STREAM frames after sending a GOAWAY frame spdySynStreamFrame.setStreamId(localStreamId); sessionHandler.offer(spdySynStreamFrame); assertRstStream(sessionHandler.poll(), localStreamId, SpdyStreamStatus.REFUSED_STREAM); assertNull(sessionHandler.peek()); // Check if session handler ignores Data frames after sending // a GOAWAY frame spdyDataFrame.setStreamId(localStreamId); sessionHandler.offer(spdyDataFrame); assertNull(sessionHandler.peek()); sessionHandler.finish(); } // Echo Handler opens 4 half-closed streams on session connection // and then sets the number of concurrent streams to 3 private static class EchoHandler extends SimpleChannelUpstreamHandler { private final int closeSignal; private final boolean server; EchoHandler(int closeSignal, boolean server) { this.closeSignal = closeSignal; this.server = server; } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Initiate 4 new streams int streamId = server ? 2 : 1; SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(streamId, 0, (byte) 0); spdySynStreamFrame.setLast(true); Channels.write(e.getChannel(), spdySynStreamFrame); spdySynStreamFrame.setStreamId(spdySynStreamFrame.getStreamId() + 2); Channels.write(e.getChannel(), spdySynStreamFrame); spdySynStreamFrame.setStreamId(spdySynStreamFrame.getStreamId() + 2); Channels.write(e.getChannel(), spdySynStreamFrame); spdySynStreamFrame.setStreamId(spdySynStreamFrame.getStreamId() + 2); Channels.write(e.getChannel(), spdySynStreamFrame); // Limit the number of concurrent streams to 1 SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame(); spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 1); Channels.write(e.getChannel(), spdySettingsFrame); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof SpdySynStreamFrame) { SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; int streamId = spdySynStreamFrame.getStreamId(); SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId); spdySynReplyFrame.setLast(spdySynStreamFrame.isLast()); for (Map.Entry entry: spdySynStreamFrame.headers()) { spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue()); } Channels.write(e.getChannel(), spdySynReplyFrame, e.getRemoteAddress()); return; } if (msg instanceof SpdySynReplyFrame) { return; } if (msg instanceof SpdyDataFrame || msg instanceof SpdyPingFrame || msg instanceof SpdyHeadersFrame) { Channels.write(e.getChannel(), msg, e.getRemoteAddress()); return; } if (msg instanceof SpdySettingsFrame) { SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; if (spdySettingsFrame.isSet(closeSignal)) { Channels.close(e.getChannel()); } } } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/string/000077500000000000000000000000001225554127700266325ustar00rootroot00000000000000AbstractSocketStringEchoTest.java000066400000000000000000000146141225554127700351660ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/string/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.TestUtil; import org.junit.Test; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; public abstract class AbstractSocketStringEchoTest { static final Random random = new Random(); static final String[] data = new String[1024]; static { for (int i = 0; i < data.length; i ++) { int eLen = random.nextInt(512); char[] e = new char[eLen]; for (int j = 0; j < eLen; j ++) { e[j] = (char) ('a' + random.nextInt(26)); } data[i] = new String(e); } } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); @Test public void testStringEcho() throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(Executors.newCachedThreadPool())); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); EchoHandler sh = new EchoHandler(); EchoHandler ch = new EchoHandler(); sb.getPipeline().addLast("framer", new DelimiterBasedFrameDecoder(512, Delimiters.lineDelimiter())); sb.getPipeline().addLast("decoder", new StringDecoder(CharsetUtil.ISO_8859_1)); sb.getPipeline().addBefore("decoder", "encoder", new StringEncoder(CharsetUtil.ISO_8859_1)); sb.getPipeline().addAfter("decoder", "handler", sh); cb.getPipeline().addLast("framer", new DelimiterBasedFrameDecoder(512, Delimiters.lineDelimiter())); cb.getPipeline().addLast("decoder", new StringDecoder(CharsetUtil.ISO_8859_1)); cb.getPipeline().addBefore("decoder", "encoder", new StringEncoder(CharsetUtil.ISO_8859_1)); cb.getPipeline().addAfter("decoder", "handler", ch); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); for (String element : data) { String delimiter = random.nextBoolean() ? "\r\n" : "\n"; cc.write(element + delimiter); } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; EchoHandler() { } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String m = (String) e.getMessage(); assertEquals(data[counter], m); if (channel.getParent() != null) { String delimiter = random.nextBoolean() ? "\r\n" : "\n"; channel.write(m + delimiter); } counter ++; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (exception.compareAndSet(null, e.getCause())) { e.getChannel().close(); } } } } NioNioSocketStringEchoTest.java000066400000000000000000000024731225554127700346160ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/string/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } NioOioSocketStringEchoTest.java000066400000000000000000000024731225554127700346170ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/string/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } OioNioSocketStringEchoTest.java000066400000000000000000000024611225554127700346140ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/string/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; public class OioNioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } OioOioSocketStringEchoTest.java000066400000000000000000000024611225554127700346150ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/codec/string/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.string; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/execution/000077500000000000000000000000001225554127700262525ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/execution/ExecutionHandlerTest.java000066400000000000000000000105321225554127700332170ustar00rootroot00000000000000/* * Copyright 2011 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.execution; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertTrue; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.DefaultChannelFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.Test; public class ExecutionHandlerTest { @Test public void testReleaseExternalResourceViaUpstreamEvent() throws Exception { Channel channel = createMock(Channel.class); expect(channel.isOpen()).andReturn(true).anyTimes(); ChannelEvent event = createMock(ChannelEvent.class); expect(event.getChannel()).andReturn(channel).anyTimes(); expect(event.getFuture()).andReturn(new DefaultChannelFuture(channel,false)).anyTimes(); replay(channel, event); final CountDownLatch latch = new CountDownLatch(1); OrderedMemoryAwareThreadPoolExecutor executor = new OrderedMemoryAwareThreadPoolExecutor(10, 0L, 0L); final ExecutionHandler handler = new ExecutionHandler(executor, true, true); handler.handleUpstream(new TestChannelHandlerContext(channel, handler, latch), event); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @Test public void testReleaseExternalResourceViaDownstreamEvent() throws Exception { Channel channel = createMock(Channel.class); expect(channel.getCloseFuture()).andReturn(new DefaultChannelFuture(channel, false)); ChannelEvent event = createMock(ChannelEvent.class); expect(event.getChannel()).andReturn(channel).anyTimes(); expect(event.getFuture()).andReturn(new DefaultChannelFuture(channel,false)).anyTimes(); replay(channel, event); final CountDownLatch latch = new CountDownLatch(1); OrderedDownstreamThreadPoolExecutor executor = new OrderedDownstreamThreadPoolExecutor(10); final ExecutionHandler handler = new ExecutionHandler(executor, true, true); handler.handleDownstream(new TestChannelHandlerContext(channel, handler, latch), event); assertTrue(latch.await(5, TimeUnit.SECONDS)); } private static final class TestChannelHandlerContext implements ChannelHandlerContext { private final CountDownLatch latch; private final ExecutionHandler handler; private final Channel channel; public TestChannelHandlerContext(Channel channel, ExecutionHandler handler, CountDownLatch latch) { this.latch = latch; this.handler = handler; this.channel = channel; } public Channel getChannel() { return channel; } public ChannelPipeline getPipeline() { return null; } public String getName() { return handler.getClass().getName(); } public ChannelHandler getHandler() { return handler; } public boolean canHandleUpstream() { return true; } public boolean canHandleDownstream() { return true; } public void sendUpstream(ChannelEvent e) { handler.releaseExternalResources(); latch.countDown(); } public void sendDownstream(ChannelEvent e) { handler.releaseExternalResources(); latch.countDown(); } public Object getAttachment() { return null; } public void setAttachment(Object attachment) { } } } MemoryAwareThreadPoolExecutorTest.java000066400000000000000000000020361225554127700356300ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/execution/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */package org.jboss.netty.handler.execution; import static org.junit.Assert.*; import org.junit.Test; public class MemoryAwareThreadPoolExecutorTest { // See https://github.com/netty/netty/issues/634 @Test public void testNPEOnUnlimetedExecutor() { MemoryAwareThreadPoolExecutor executor = new MemoryAwareThreadPoolExecutor(2, 0, 0); assertEquals(0, executor.getMaxTotalMemorySize()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ipfilter/000077500000000000000000000000001225554127700260655ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ipfilter/IpFilterRuleTest.java000066400000000000000000000201651225554127700321420ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelConfig; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.UpstreamMessageEvent; import org.junit.Test; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import static org.junit.Assert.*; public class IpFilterRuleTest { public static boolean accept(IpFilterRuleHandler h, InetSocketAddress addr) throws Exception { System.err.print("accept(rules("); for (int i = 0; i < h.size(); i ++) { final IpFilterRule rule = h.get(i); if (rule.isAllowRule()) { System.err.print("allow("); } else { System.err.print("deny("); } if (rule instanceof PatternRule) { System.err.print(((PatternRule) rule).getPattern()); } else { System.err.print(rule); } System.err.print(')'); if (i != h.size() - 1) { System.err.print(", "); } } System.err.print("), "); System.err.print(addr); System.err.print(") = "); boolean result = h.accept(new ChannelHandlerContext() { public boolean canHandleDownstream() { return false; } public boolean canHandleUpstream() { return false; } public Object getAttachment() { return null; } public Channel getChannel() { return null; } public ChannelHandler getHandler() { return null; } public String getName() { return null; } public ChannelPipeline getPipeline() { return null; } public void sendDownstream(ChannelEvent e) { // NOOP } public void sendUpstream(ChannelEvent e) { // NOOP } public void setAttachment(Object attachment) { // NOOP } }, new UpstreamMessageEvent(new Channel() { public ChannelFuture bind(SocketAddress localAddress) { return null; } public ChannelFuture close() { return null; } public ChannelFuture connect(SocketAddress remoteAddress) { return null; } public ChannelFuture disconnect() { return null; } public ChannelFuture getCloseFuture() { return null; } public ChannelConfig getConfig() { return null; } public ChannelFactory getFactory() { return null; } public Integer getId() { return null; } public int getInterestOps() { return 0; } public SocketAddress getLocalAddress() { return null; } public Channel getParent() { return null; } public ChannelPipeline getPipeline() { return null; } public SocketAddress getRemoteAddress() { return null; } public boolean isBound() { return false; } public boolean isConnected() { return false; } public boolean isOpen() { return false; } public boolean isReadable() { return false; } public boolean isWritable() { return false; } public ChannelFuture setInterestOps(int interestOps) { return null; } public ChannelFuture setReadable(boolean readable) { return null; } public ChannelFuture unbind() { return null; } public ChannelFuture write(Object message) { return null; } public ChannelFuture write(Object message, SocketAddress remoteAddress) { return null; } public int compareTo(Channel o) { return 0; } public int hashCode() { return 0; } public boolean equals(Object o) { return this == o; } public Object getAttachment() { return null; } public void setAttachment(Object attachment) { // NOOP } }, h, addr), addr); System.err.println(result); return result; } @Test public void testIpFilterRule() throws Exception { IpFilterRuleHandler h = new IpFilterRuleHandler(); h.addAll(new IpFilterRuleList("+n:localhost, -n:*")); InetSocketAddress addr = new InetSocketAddress(InetAddress.getLocalHost(), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName("127.0.0.2"), 8080); assertFalse(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName(InetAddress.getLocalHost().getHostName()), 8080); assertTrue(accept(h, addr)); h.clear(); h.addAll(new IpFilterRuleList("+n:*" + InetAddress.getLocalHost().getHostName().substring(1) + ", -n:*")); addr = new InetSocketAddress(InetAddress.getLocalHost(), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName("127.0.0.2"), 8080); assertFalse(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName(InetAddress.getLocalHost().getHostName()), 8080); assertTrue(accept(h, addr)); h.clear(); h.addAll(new IpFilterRuleList("+c:" + InetAddress.getLocalHost().getHostAddress() + "/32, -n:*")); addr = new InetSocketAddress(InetAddress.getLocalHost(), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName("127.0.0.2"), 8080); assertFalse(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName(InetAddress.getLocalHost().getHostName()), 8080); assertTrue(accept(h, addr)); h.clear(); h.addAll(new IpFilterRuleList("")); addr = new InetSocketAddress(InetAddress.getLocalHost(), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName("127.0.0.2"), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName(InetAddress.getLocalHost().getHostName()), 8080); assertTrue(accept(h, addr)); h.clear(); addr = new InetSocketAddress(InetAddress.getLocalHost(), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName("127.0.0.2"), 8080); assertTrue(accept(h, addr)); addr = new InetSocketAddress(InetAddress.getByName(InetAddress.getLocalHost().getHostName()), 8080); assertTrue(accept(h, addr)); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/000077500000000000000000000000001225554127700250505ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/AbstractSocketSslEchoTest.java000066400000000000000000000177001225554127700327550ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.execution.ExecutionHandler; import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.util.TestUtil; import org.junit.Test; import javax.net.ssl.SSLEngine; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; public abstract class AbstractSocketSslEchoTest { static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractSocketSslEchoTest.class); private static final Random random = new Random(); static final byte[] data = new byte[1048576]; static { random.nextBytes(data); } protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); protected boolean isExecutorRequired() { return false; } @Test public void testSslEcho() throws Throwable { ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(Executors.newCachedThreadPool())); ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(Executors.newCachedThreadPool())); EchoHandler sh = new EchoHandler(true); EchoHandler ch = new EchoHandler(false); SSLEngine sse = SecureChatSslContextFactory.getServerContext().createSSLEngine(); SSLEngine cse = SecureChatSslContextFactory.getClientContext().createSSLEngine(); sse.setUseClientMode(false); cse.setUseClientMode(true); // Workaround for blocking I/O transport write-write dead lock. sb.setOption("receiveBufferSize", 1048576); sb.setOption("receiveBufferSize", 1048576); sb.getPipeline().addFirst("ssl", new SslHandler(sse)); sb.getPipeline().addLast("handler", sh); cb.getPipeline().addFirst("ssl", new SslHandler(cse)); cb.getPipeline().addLast("handler", ch); ExecutorService eventExecutor = null; if (isExecutorRequired()) { eventExecutor = new OrderedMemoryAwareThreadPoolExecutor(16, 0, 0); sb.getPipeline().addFirst("executor", new ExecutionHandler(eventExecutor)); cb.getPipeline().addFirst("executor", new ExecutionHandler(eventExecutor)); } Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); ccf.awaitUninterruptibly(); if (!ccf.isSuccess()) { logger.error("Connection attempt failed", ccf.getCause()); sc.close().awaitUninterruptibly(); } assertTrue(ccf.isSuccess()); Channel cc = ccf.getChannel(); ChannelFuture hf = cc.getPipeline().get(SslHandler.class).handshake(); hf.awaitUninterruptibly(); if (!hf.isSuccess()) { logger.error("Handshake failed", hf.getCause()); sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); } assertTrue(hf.isSuccess()); for (int i = 0; i < data.length;) { int length = Math.min(random.nextInt(1024 * 64), data.length - i); cc.write(ChannelBuffers.wrappedBuffer(data, i, length)); i += length; } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().awaitUninterruptibly(); ch.channel.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly(); cb.shutdown(); sb.shutdown(); cb.releaseExternalResources(); sb.releaseExternalResources(); if (eventExecutor != null) { eventExecutor.shutdown(); } if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; private final boolean server; EchoHandler(boolean server) { this.server = server; } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer m = (ChannelBuffer) e.getMessage(); byte[] actual = new byte[m.readableBytes()]; m.getBytes(0, actual); int lastIdx = counter; for (int i = 0; i < actual.length; i ++) { assertEquals(data[i + lastIdx], actual[i]); } if (channel.getParent() != null) { channel.write(m); } counter += actual.length; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { logger.warn( "Unexpected exception from the " + (server? "server" : "client") + " side", e.getCause()); exception.compareAndSet(null, e.getCause()); e.getChannel().close(); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/ImmediateExecutorTest.java000066400000000000000000000027311225554127700321730ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import static org.junit.Assert.*; import org.junit.Test; public class ImmediateExecutorTest { @Test public void shouldExecuteImmediately() { ImmediateExecutor e = ImmediateExecutor.INSTANCE; long startTime = System.nanoTime(); e.execute(new Runnable() { public void run() { long startTime = System.nanoTime(); for (;;) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } if (System.nanoTime() - startTime >= 1000000000L) { break; } } } }); assertTrue(System.nanoTime() - startTime >= 1000000000L); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/NioNioSocketSslEchoTest.java000066400000000000000000000024541225554127700324050ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class NioNioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/NioOioSocketSslEchoTest.java000066400000000000000000000024541225554127700324060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class NioOioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new NioClientSocketChannelFactory(executor, executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/OioNioSocketSslEchoTest.java000066400000000000000000000024421225554127700324030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; public class OioNioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new NioServerSocketChannelFactory(executor, executor); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/OioOioSocketSslEchoTest.java000066400000000000000000000025701225554127700324060ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import java.util.concurrent.Executor; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; public class OioOioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override protected ChannelFactory newClientSocketChannelFactory(Executor executor) { return new OioClientSocketChannelFactory(executor); } @Override protected ChannelFactory newServerSocketChannelFactory(Executor executor) { return new OioServerSocketChannelFactory(executor, executor); } @Override protected boolean isExecutorRequired() { return true; } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/SslCloseTest.java000066400000000000000000000053121225554127700303030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import java.net.InetSocketAddress; import javax.net.ssl.SSLEngine; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; public class SslCloseTest { /** * Try to write a testcase to reproduce #343 */ @Test public void testCloseOnSslException() { ServerBootstrap sb = new ServerBootstrap(new NioServerSocketChannelFactory()); ClientBootstrap cb = new ClientBootstrap(new NioClientSocketChannelFactory()); SSLEngine sse = SecureChatSslContextFactory.getServerContext().createSSLEngine(); sse.setUseClientMode(false); sb.getPipeline().addFirst("ssl", new SslHandler(sse)); sb.getPipeline().addLast("handler", new SimpleChannelUpstreamHandler() { @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); System.out.println("Close channel"); ctx.getChannel().close(); } }); Channel serverChannel = sb.bind(new InetSocketAddress(0)); Channel cc = cb.connect(serverChannel.getLocalAddress()).awaitUninterruptibly().getChannel(); cc.write(ChannelBuffers.copiedBuffer("unencrypted", CharsetUtil.US_ASCII)).awaitUninterruptibly(); Assert.assertTrue(cc.getCloseFuture().awaitUninterruptibly(5000)); serverChannel.close(); cb.releaseExternalResources(); sb.releaseExternalResources(); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/SslHandlerTest.java000066400000000000000000000031741225554127700306170ustar00rootroot00000000000000 /* * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; import org.jboss.netty.handler.codec.embedder.DecoderEmbedder; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import java.util.Random; public class SslHandlerTest { private final Random random = new Random(); @Test @Ignore public void testDetectNonSslRecord() { byte[] data = new byte[1024]; random.nextBytes(data); DecoderEmbedder em = new DecoderEmbedder(new SslHandler(SecureChatSslContextFactory.getServerContext().createSSLEngine())); try { em.offer(ChannelBuffers.wrappedBuffer(data)); Assert.fail(); } catch (CodecEmbedderException e) { Assert.assertTrue(e.getCause() instanceof NotSslRecordException); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/ssl/SslHandshakeRaceTester.java000066400000000000000000000165441225554127700322570ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ssl; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.ServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; import org.jboss.netty.example.securechat.SecureChatSslContextFactory; import javax.net.ssl.SSLEngine; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.atomic.AtomicReference; public class SslHandshakeRaceTester { private static final Random random = new Random(); static final byte[] data = new byte[1048576]; private int count; static { random.nextBytes(data); } public void run(int rounds, boolean nio) throws Throwable { ClientSocketChannelFactory clientFactory; if (nio) { clientFactory = new NioClientSocketChannelFactory(); } else { clientFactory = new OioClientSocketChannelFactory(); } ClientBootstrap cb = new ClientBootstrap(clientFactory); cb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline cp = Channels.pipeline(); SSLEngine cse = SecureChatSslContextFactory.getClientContext().createSSLEngine(); cse.setUseClientMode(true); cp.addFirst("ssl", new SslHandler(cse)); cp.addLast("handler", new TestHandler()); return cp; } }); ServerSocketChannelFactory serverFactory; if (nio) { serverFactory = new NioServerSocketChannelFactory(); } else { serverFactory = new OioServerSocketChannelFactory(); } ServerBootstrap sb = new ServerBootstrap(serverFactory); sb.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline cp = Channels.pipeline(); cp.addFirst("counter", new SimpleChannelUpstreamHandler() { @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.getPipeline().get(SslHandler.class).handshake().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { future.getCause().printStackTrace(); future.getChannel().close(); } } }); ++count; System.out.println("Connection #" + count); } }); SSLEngine sse = SecureChatSslContextFactory.getServerContext().createSSLEngine(); sse.setUseClientMode(false); cp.addFirst("ssl", new SslHandler(sse)); cp.addLast("handler", new TestHandler()); return cp; } }); Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); for (int i = 0; i < rounds; i++) { connectAndSend(cb, port); } cb.shutdown(); cb.releaseExternalResources(); sc.close().awaitUninterruptibly(); sb.shutdown(); sb.releaseExternalResources(); } private static void connectAndSend(ClientBootstrap cb, int port) throws Throwable { ChannelFuture ccf = cb.connect(new InetSocketAddress("127.0.0.1", port)); ccf.awaitUninterruptibly(); if (!ccf.isSuccess()) { ccf.getCause().printStackTrace(); throw ccf.getCause(); } TestHandler ch = ccf.getChannel().getPipeline().get(TestHandler.class); Channel cc = ccf.getChannel(); ChannelFuture hf = cc.getPipeline().get(SslHandler.class).handshake(); hf.awaitUninterruptibly(); if (!hf.isSuccess()) { hf.getCause().printStackTrace(); ch.channel.close(); throw hf.getCause(); } for (int i = 0; i < data.length;) { int length = Math.min(random.nextInt(1024 * 64), data.length - i); ChannelFuture future = cc.write(ChannelBuffers.wrappedBuffer(data, i, length)); i += length; if (i >= data.length) { future.awaitUninterruptibly(); } } ch.channel.close().awaitUninterruptibly(); if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class TestHandler extends SimpleChannelUpstreamHandler { volatile Channel channel; final AtomicReference exception = new AtomicReference(); @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { channel = e.getChannel(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); exception.compareAndSet(null, e.getCause()); e.getChannel().close(); } } public static void main(String[] args) throws Throwable { int count = 20000; boolean nio = false; if (args.length == 2) { count = Integer.parseInt(args[0]); nio = Boolean.parseBoolean(args[1]); } SslHandshakeRaceTester test = new SslHandshakeRaceTester(); test.run(count, nio); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/stream/000077500000000000000000000000001225554127700255425ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/handler/stream/ChunkedWriteHandlerTest.java000066400000000000000000000147171225554127700331510ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.stream; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelDownstreamHandler; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.jboss.netty.util.CharsetUtil; import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.Channels; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.*; public class ChunkedWriteHandlerTest { private static final byte[] BYTES = new byte[1024 * 64]; private static final File TMP; static { for (int i = 0; i < BYTES.length; i++) { BYTES[i] = (byte) i; } FileOutputStream out = null; try { TMP = File.createTempFile("netty-chunk-", ".tmp"); TMP.deleteOnExit(); out = new FileOutputStream(TMP); out.write(BYTES); out.flush(); } catch (IOException e) { throw new RuntimeException(e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { // ignore } } } } // See #310 @Test public void testChunkedStream() { check(new ChunkedStream(new ByteArrayInputStream(BYTES))); check(new ChunkedStream(new ByteArrayInputStream(BYTES)), new ChunkedStream(new ByteArrayInputStream(BYTES)), new ChunkedStream(new ByteArrayInputStream(BYTES))); } @Test public void testChunkedNioStream() { check(new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES)))); check(new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES))), new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES))), new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES)))); } // Test case which shows that there is not a bug like stated here: // http://stackoverflow.com/questions/10409241/why-is-close-channelfuturelistener-not-notified/10426305#comment14126161_10426305 @Test public void testListenerNotifiedWhenIsEnd() { ChannelBuffer buffer = ChannelBuffers.copiedBuffer("Test", CharsetUtil.ISO_8859_1); ChunkedInput input = new ChunkedInput() { private boolean done; private final ChannelBuffer buffer = ChannelBuffers.copiedBuffer("Test", CharsetUtil.ISO_8859_1); public Object nextChunk() throws Exception { done = true; return buffer.duplicate(); } public boolean isEndOfInput() throws Exception { return done; } public boolean hasNextChunk() throws Exception { return true; } public void close() throws Exception { } }; final AtomicBoolean listenerNotified = new AtomicBoolean(false); final ChannelFutureListener listener = new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { listenerNotified.set(true); } }; SimpleChannelDownstreamHandler testHandler = new SimpleChannelDownstreamHandler() { @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { super.writeRequested(ctx, e); e.getFuture().setSuccess(); } }; EncoderEmbedder handler = new EncoderEmbedder(new ChunkedWriteHandler(), testHandler) { @Override public boolean offer(Object input) { ChannelFuture future = org.jboss.netty.channel.Channels.write(getChannel(), input); future.addListener(listener); future.awaitUninterruptibly(); return !isEmpty(); } }; assertTrue(handler.offer(input)); assertTrue(handler.finish()); // the listener should have been notified assertTrue(listenerNotified.get()); assertEquals(buffer, handler.poll()); assertNull(handler.poll()); } @Test public void testChunkedFile() throws IOException { check(new ChunkedFile(TMP)); check(new ChunkedFile(TMP), new ChunkedFile(TMP), new ChunkedFile(TMP)); } @Test public void testChunkedNioFile() throws IOException { check(new ChunkedNioFile(TMP)); check(new ChunkedNioFile(TMP), new ChunkedNioFile(TMP), new ChunkedNioFile(TMP)); } private static void check(ChunkedInput... inputs) { EncoderEmbedder embedder = new EncoderEmbedder(new ChunkedWriteHandler()); for (ChunkedInput input: inputs) { embedder.offer(input); } assertTrue(embedder.finish()); int i = 0; int read = 0; for (;;) { ChannelBuffer buffer = embedder.poll(); if (buffer == null) { break; } while (buffer.readable()) { assertEquals(BYTES[i++], buffer.readByte()); read++; if (i == BYTES.length) { i = 0; } } } assertEquals(BYTES.length * inputs.length, read); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/000077500000000000000000000000001225554127700242605ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/CommonsLoggerFactoryTest.java000066400000000000000000000017501225554127700320710ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.junit.Assert.*; import org.junit.Test; public class CommonsLoggerFactoryTest { @Test public void testCreation() { InternalLogger logger = new CommonsLoggerFactory().newInstance("foo"); assertTrue(logger instanceof CommonsLogger); assertEquals("foo", logger.toString()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/CommonsLoggerTest.java000066400000000000000000000104731225554127700305430ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.apache.commons.logging.Log; import org.junit.Test; public class CommonsLoggerTest { private static final Exception e = new Exception(); @Test public void testIsDebugEnabled() { Log mock = createStrictMock(Log.class); expect(mock.isDebugEnabled()).andReturn(true); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); assertTrue(logger.isDebugEnabled()); verify(mock); } @Test public void testIsInfoEnabled() { Log mock = createStrictMock(Log.class); expect(mock.isInfoEnabled()).andReturn(true); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); assertTrue(logger.isInfoEnabled()); verify(mock); } @Test public void testIsWarnEnabled() { Log mock = createStrictMock(Log.class); expect(mock.isWarnEnabled()).andReturn(true); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); assertTrue(logger.isWarnEnabled()); verify(mock); } @Test public void testIsErrorEnabled() { Log mock = createStrictMock(Log.class); expect(mock.isErrorEnabled()).andReturn(true); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); assertTrue(logger.isErrorEnabled()); verify(mock); } @Test public void testDebug() { Log mock = createStrictMock(Log.class); mock.debug("a"); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.debug("a"); verify(mock); } @Test public void testDebugWithException() { Log mock = createStrictMock(Log.class); mock.debug("a", e); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.debug("a", e); verify(mock); } @Test public void testInfo() { Log mock = createStrictMock(Log.class); mock.info("a"); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.info("a"); verify(mock); } @Test public void testInfoWithException() { Log mock = createStrictMock(Log.class); mock.info("a", e); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.info("a", e); verify(mock); } @Test public void testWarn() { Log mock = createStrictMock(Log.class); mock.warn("a"); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.warn("a"); verify(mock); } @Test public void testWarnWithException() { Log mock = createStrictMock(Log.class); mock.warn("a", e); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.warn("a", e); verify(mock); } @Test public void testError() { Log mock = createStrictMock(Log.class); mock.error("a"); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.error("a"); verify(mock); } @Test public void testErrorWithException() { Log mock = createStrictMock(Log.class); mock.error("a", e); replay(mock); InternalLogger logger = new CommonsLogger(mock, "foo"); logger.error("a", e); verify(mock); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/InternalLoggerFactoryTest.java000066400000000000000000000112411225554127700322260ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; public class InternalLoggerFactoryTest { private static final Exception e = new Exception(); private InternalLoggerFactory oldLoggerFactory; private InternalLogger mock; @Before public void init() { oldLoggerFactory = InternalLoggerFactory.getDefaultFactory(); InternalLoggerFactory mockFactory = createMock(InternalLoggerFactory.class); mock = createStrictMock(InternalLogger.class); expect(mockFactory.newInstance("mock")).andReturn(mock).anyTimes(); replay(mockFactory); InternalLoggerFactory.setDefaultFactory(mockFactory); } @After public void destroy() { reset(mock); InternalLoggerFactory.setDefaultFactory(oldLoggerFactory); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullDefaultFactory() { InternalLoggerFactory.setDefaultFactory(null); } @Test public void shouldReturnWrappedLogger() { assertNotSame(mock, InternalLoggerFactory.getInstance("mock")); } @Test public void testIsDebugEnabled() { expect(mock.isDebugEnabled()).andReturn(true); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); assertTrue(logger.isDebugEnabled()); verify(mock); } @Test public void testIsInfoEnabled() { expect(mock.isInfoEnabled()).andReturn(true); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); assertTrue(logger.isInfoEnabled()); verify(mock); } @Test public void testIsWarnEnabled() { expect(mock.isWarnEnabled()).andReturn(true); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); assertTrue(logger.isWarnEnabled()); verify(mock); } @Test public void testIsErrorEnabled() { expect(mock.isErrorEnabled()).andReturn(true); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); assertTrue(logger.isErrorEnabled()); verify(mock); } @Test public void testDebug() { mock.debug("a"); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.debug("a"); verify(mock); } @Test public void testDebugWithException() { mock.debug("a", e); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.debug("a", e); verify(mock); } @Test public void testInfo() { mock.info("a"); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.info("a"); verify(mock); } @Test public void testInfoWithException() { mock.info("a", e); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.info("a", e); verify(mock); } @Test public void testWarn() { mock.warn("a"); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.warn("a"); verify(mock); } @Test public void testWarnWithException() { mock.warn("a", e); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.warn("a", e); verify(mock); } @Test public void testError() { mock.error("a"); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.error("a"); verify(mock); } @Test public void testErrorWithException() { mock.error("a", e); replay(mock); InternalLogger logger = InternalLoggerFactory.getInstance("mock"); logger.error("a", e); verify(mock); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/JBossLoggerFactoryTest.java000066400000000000000000000017421225554127700314770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.junit.Assert.*; import org.junit.Test; public class JBossLoggerFactoryTest { @Test public void testCreation() { InternalLogger logger = new JBossLoggerFactory().newInstance("foo"); assertTrue(logger instanceof JBossLogger); assertEquals("foo", logger.toString()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/JBossLoggerTest.java000066400000000000000000000103521225554127700301440ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.jboss.logging.Logger; import org.junit.Test; public class JBossLoggerTest { private static final Exception e = new Exception(); @Test @SuppressWarnings("deprecation") public void testIsDebugEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isDebugEnabled()).andReturn(true); replay(mock); InternalLogger logger = new JBossLogger(mock); assertTrue(logger.isDebugEnabled()); verify(mock); } @Test @SuppressWarnings("deprecation") public void testIsInfoEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isInfoEnabled()).andReturn(true); replay(mock); InternalLogger logger = new JBossLogger(mock); assertTrue(logger.isInfoEnabled()); verify(mock); } @Test public void testIsWarnEnabled() { Logger mock = createStrictMock(Logger.class); replay(mock); InternalLogger logger = new JBossLogger(mock); assertTrue(logger.isWarnEnabled()); verify(mock); } @Test public void testIsErrorEnabled() { Logger mock = createStrictMock(Logger.class); replay(mock); InternalLogger logger = new JBossLogger(mock); assertTrue(logger.isErrorEnabled()); verify(mock); } @Test public void testDebug() { Logger mock = createStrictMock(Logger.class); mock.debug("a"); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.debug("a"); verify(mock); } @Test public void testDebugWithException() { Logger mock = createStrictMock(Logger.class); mock.debug("a", e); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.debug("a", e); verify(mock); } @Test public void testInfo() { Logger mock = createStrictMock(Logger.class); mock.info("a"); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.info("a"); verify(mock); } @Test public void testInfoWithException() { Logger mock = createStrictMock(Logger.class); mock.info("a", e); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.info("a", e); verify(mock); } @Test public void testWarn() { Logger mock = createStrictMock(Logger.class); mock.warn("a"); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.warn("a"); verify(mock); } @Test public void testWarnWithException() { Logger mock = createStrictMock(Logger.class); mock.warn("a", e); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.warn("a", e); verify(mock); } @Test public void testError() { Logger mock = createStrictMock(Logger.class); mock.error("a"); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.error("a"); verify(mock); } @Test public void testErrorWithException() { Logger mock = createStrictMock(Logger.class); mock.error("a", e); replay(mock); InternalLogger logger = new JBossLogger(mock); logger.error("a", e); verify(mock); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/JdkLoggerFactoryTest.java000066400000000000000000000017341225554127700311700ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.junit.Assert.*; import org.junit.Test; public class JdkLoggerFactoryTest { @Test public void testCreation() { InternalLogger logger = new JdkLoggerFactory().newInstance("foo"); assertTrue(logger instanceof JdkLogger); assertEquals("foo", logger.toString()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/JdkLoggerTest.java000066400000000000000000000111301225554127700276270ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.util.logging.Level; import java.util.logging.Logger; import org.junit.Test; public class JdkLoggerTest { private static final Exception e = new Exception(); @Test public void testIsDebugEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isLoggable(Level.FINE)).andReturn(true); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); assertTrue(logger.isDebugEnabled()); verify(mock); } @Test public void testIsInfoEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isLoggable(Level.INFO)).andReturn(true); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); assertTrue(logger.isInfoEnabled()); verify(mock); } @Test public void testIsWarnEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isLoggable(Level.WARNING)).andReturn(true); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); assertTrue(logger.isWarnEnabled()); verify(mock); } @Test public void testIsErrorEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isLoggable(Level.SEVERE)).andReturn(true); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); assertTrue(logger.isErrorEnabled()); verify(mock); } @Test public void testDebug() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.FINE, "foo", null, "a"); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.debug("a"); verify(mock); } @Test public void testDebugWithException() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.FINE, "foo", null, "a", e); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.debug("a", e); verify(mock); } @Test public void testInfo() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.INFO, "foo", null, "a"); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.info("a"); verify(mock); } @Test public void testInfoWithException() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.INFO, "foo", null, "a", e); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.info("a", e); verify(mock); } @Test public void testWarn() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.WARNING, "foo", null, "a"); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.warn("a"); verify(mock); } @Test public void testWarnWithException() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.WARNING, "foo", null, "a", e); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.warn("a", e); verify(mock); } @Test public void testError() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.SEVERE, "foo", null, "a"); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.error("a"); verify(mock); } @Test public void testErrorWithException() { Logger mock = createStrictMock(Logger.class); mock.logp(Level.SEVERE, "foo", null, "a", e); replay(mock); InternalLogger logger = new JdkLogger(mock, "foo"); logger.error("a", e); verify(mock); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/Log4JLoggerFactoryTest.java000066400000000000000000000017421225554127700313760ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.junit.Assert.*; import org.junit.Test; public class Log4JLoggerFactoryTest { @Test public void testCreation() { InternalLogger logger = new Log4JLoggerFactory().newInstance("foo"); assertTrue(logger instanceof Log4JLogger); assertEquals("foo", logger.toString()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/Log4JLoggerTest.java000066400000000000000000000102411225554127700300400ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.apache.log4j.Logger; import org.junit.Test; public class Log4JLoggerTest { private static final Exception e = new Exception(); @Test public void testIsDebugEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isDebugEnabled()).andReturn(true); replay(mock); InternalLogger logger = new Log4JLogger(mock); assertTrue(logger.isDebugEnabled()); verify(mock); } @Test public void testIsInfoEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isInfoEnabled()).andReturn(true); replay(mock); InternalLogger logger = new Log4JLogger(mock); assertTrue(logger.isInfoEnabled()); verify(mock); } @Test public void testIsWarnEnabled() { Logger mock = createStrictMock(Logger.class); replay(mock); InternalLogger logger = new Log4JLogger(mock); assertTrue(logger.isWarnEnabled()); verify(mock); } @Test public void testIsErrorEnabled() { Logger mock = createStrictMock(Logger.class); replay(mock); InternalLogger logger = new Log4JLogger(mock); assertTrue(logger.isErrorEnabled()); verify(mock); } @Test public void testDebug() { Logger mock = createStrictMock(Logger.class); mock.debug("a"); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.debug("a"); verify(mock); } @Test public void testDebugWithException() { Logger mock = createStrictMock(Logger.class); mock.debug("a", e); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.debug("a", e); verify(mock); } @Test public void testInfo() { Logger mock = createStrictMock(Logger.class); mock.info("a"); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.info("a"); verify(mock); } @Test public void testInfoWithException() { Logger mock = createStrictMock(Logger.class); mock.info("a", e); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.info("a", e); verify(mock); } @Test public void testWarn() { Logger mock = createStrictMock(Logger.class); mock.warn("a"); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.warn("a"); verify(mock); } @Test public void testWarnWithException() { Logger mock = createStrictMock(Logger.class); mock.warn("a", e); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.warn("a", e); verify(mock); } @Test public void testError() { Logger mock = createStrictMock(Logger.class); mock.error("a"); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.error("a"); verify(mock); } @Test public void testErrorWithException() { Logger mock = createStrictMock(Logger.class); mock.error("a", e); replay(mock); InternalLogger logger = new Log4JLogger(mock); logger.error("a", e); verify(mock); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/Slf4JLoggerFactoryTest.java000066400000000000000000000017421225554127700314010ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.junit.Assert.*; import org.junit.Test; public class Slf4JLoggerFactoryTest { @Test public void testCreation() { InternalLogger logger = new Slf4JLoggerFactory().newInstance("foo"); assertTrue(logger instanceof Slf4JLogger); assertEquals("foo", logger.toString()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/logging/Slf4JLoggerTest.java000066400000000000000000000104071225554127700300470ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.logging; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.junit.Test; import org.slf4j.Logger; public class Slf4JLoggerTest { private static final Exception e = new Exception(); @Test public void testIsDebugEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isDebugEnabled()).andReturn(true); replay(mock); InternalLogger logger = new Slf4JLogger(mock); assertTrue(logger.isDebugEnabled()); verify(mock); } @Test public void testIsInfoEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isInfoEnabled()).andReturn(true); replay(mock); InternalLogger logger = new Slf4JLogger(mock); assertTrue(logger.isInfoEnabled()); verify(mock); } @Test public void testIsWarnEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isWarnEnabled()).andReturn(true); replay(mock); InternalLogger logger = new Slf4JLogger(mock); assertTrue(logger.isWarnEnabled()); verify(mock); } @Test public void testIsErrorEnabled() { Logger mock = createStrictMock(Logger.class); expect(mock.isErrorEnabled()).andReturn(true); replay(mock); InternalLogger logger = new Slf4JLogger(mock); assertTrue(logger.isErrorEnabled()); verify(mock); } @Test public void testDebug() { Logger mock = createStrictMock(Logger.class); mock.debug("a"); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.debug("a"); verify(mock); } @Test public void testDebugWithException() { Logger mock = createStrictMock(Logger.class); mock.debug("a", e); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.debug("a", e); verify(mock); } @Test public void testInfo() { Logger mock = createStrictMock(Logger.class); mock.info("a"); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.info("a"); verify(mock); } @Test public void testInfoWithException() { Logger mock = createStrictMock(Logger.class); mock.info("a", e); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.info("a", e); verify(mock); } @Test public void testWarn() { Logger mock = createStrictMock(Logger.class); mock.warn("a"); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.warn("a"); verify(mock); } @Test public void testWarnWithException() { Logger mock = createStrictMock(Logger.class); mock.warn("a", e); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.warn("a", e); verify(mock); } @Test public void testError() { Logger mock = createStrictMock(Logger.class); mock.error("a"); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.error("a"); verify(mock); } @Test public void testErrorWithException() { Logger mock = createStrictMock(Logger.class); mock.error("a", e); replay(mock); InternalLogger logger = new Slf4JLogger(mock); logger.error("a", e); verify(mock); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/000077500000000000000000000000001225554127700236075ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/DummyHandler.java000066400000000000000000000024301225554127700270420ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelUpstreamHandler; /** * A dummy handler for a testing purpose. */ public class DummyHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler { public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { ctx.sendUpstream(e); } public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { ctx.sendDownstream(e); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/HashedWheelTimerTest.java000066400000000000000000000112171225554127700304760ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.junit.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class HashedWheelTimerTest { @Test public void testScheduleTimeoutShouldNotRunBeforeDelay() throws InterruptedException { final Timer timer = new HashedWheelTimer(); final CountDownLatch barrier = new CountDownLatch(1); final Timeout timeout = timer.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { fail("This should not have run"); barrier.countDown(); } }, 10, TimeUnit.SECONDS); assertFalse(barrier.await(3, TimeUnit.SECONDS)); assertFalse("timer should not expire", timeout.isExpired()); timer.stop(); } @Test public void testScheduleTimeoutShouldRunAfterDelay() throws InterruptedException { final Timer timer = new HashedWheelTimer(); final CountDownLatch barrier = new CountDownLatch(1); final Timeout timeout = timer.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { barrier.countDown(); } }, 2, TimeUnit.SECONDS); assertTrue(barrier.await(3, TimeUnit.SECONDS)); assertTrue("timer should expire", timeout.isExpired()); timer.stop(); } @Test public void testStopTimer() throws InterruptedException { final Timer timerProcessed = new HashedWheelTimer(); for (int i = 0; i < 3; i ++) { timerProcessed.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { } }, 1, TimeUnit.MILLISECONDS); } Thread.sleep(1000L); // sleep for a second assertEquals("Number of unprocessed timeouts should be 0", 0, timerProcessed.stop().size()); final Timer timerUnprocessed = new HashedWheelTimer(); for (int i = 0; i < 5; i ++) { timerUnprocessed.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { } }, 5, TimeUnit.SECONDS); } Thread.sleep(1000L); // sleep for a second assertFalse("Number of unprocessed timeouts should be greater than 0", timerUnprocessed.stop().isEmpty()); } @Test(expected = IllegalStateException.class) public void testTimerShouldThrowExceptionAfterShutdownForNewTimeouts() throws InterruptedException { final Timer timer = new HashedWheelTimer(); for (int i = 0; i < 3; i ++) { timer.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { } }, 1, TimeUnit.MILLISECONDS); } timer.stop(); Thread.sleep(1000L); // sleep for a second timer.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { fail("This should not run"); } }, 1, TimeUnit.SECONDS); } @Test public void testTimerOverflowWheelLength() throws InterruptedException { final HashedWheelTimer timer = new HashedWheelTimer( Executors.defaultThreadFactory(), 100, TimeUnit.MILLISECONDS, 32); final AtomicInteger counter = new AtomicInteger(); timer.newTimeout(new TimerTask() { public void run(final Timeout timeout) throws Exception { counter.incrementAndGet(); timer.newTimeout(this, 1, TimeUnit.SECONDS); } }, 1, TimeUnit.SECONDS); Thread.sleep(3500); assertEquals(3, counter.get()); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/MapBackedSetTest.java000066400000000000000000000060551225554127700276030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.junit.Test; public class MapBackedSetTest { @Test @SuppressWarnings({ "unchecked", "rawtypes" }) public void testSize() { Map map = createStrictMock(Map.class); expect(map.size()).andReturn(0); replay(map); assertEquals(0, new MapBackedSet(map).size()); verify(map); } @Test @SuppressWarnings({ "unchecked", "rawtypes" }) public void testContains() { Map map = createStrictMock(Map.class); expect(map.containsKey("key")).andReturn(true); replay(map); assertTrue(new MapBackedSet(map).contains("key")); verify(map); } @Test @SuppressWarnings({ "unchecked", "rawtypes" }) public void testRemove() { Map map = createStrictMock(Map.class); expect(map.remove("key")).andReturn(true); expect(map.remove("key")).andReturn(null); replay(map); assertTrue(new MapBackedSet(map).remove("key")); assertFalse(new MapBackedSet(map).remove("key")); verify(map); } @Test @SuppressWarnings({"unchecked", "rawtypes"}) public void testAdd() { Map map = createStrictMock(Map.class); expect(map.put("key", true)).andReturn(null); expect(map.put("key", true)).andReturn(true); replay(map); assertTrue(new MapBackedSet(map).add("key")); assertFalse(new MapBackedSet(map).add("key")); verify(map); } @Test @SuppressWarnings({ "unchecked", "rawtypes" }) public void testClear() { Map map = createStrictMock(Map.class); map.clear(); replay(map); new MapBackedSet(map).clear(); verify(map); } @Test @SuppressWarnings({ "unchecked", "rawtypes" }) public void testIterator() { Map map = createStrictMock(Map.class); Set keySet = createStrictMock(Set.class); Iterator keySetIterator = createStrictMock(Iterator.class); expect(map.keySet()).andReturn(keySet); expect(keySet.iterator()).andReturn(keySetIterator); replay(map); replay(keySet); replay(keySetIterator); assertSame(keySetIterator, new MapBackedSet(map).iterator()); verify(map); verify(keySet); verify(keySetIterator); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/NetUtilTest.java000066400000000000000000000303361225554127700267030ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.junit.Test; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import static org.junit.Assert.*; public class NetUtilTest { private final static Map validIpV4Hosts = new HashMap() { private static final long serialVersionUID = 2629792739366724032L; { put("192.168.1.0", new byte[]{ (byte) 0xc0, (byte) 0xa8, 0x01, 0x00} ); put("10.255.255.254", new byte[]{ 0x0a, (byte) 0xff, (byte) 0xff, (byte) 0xfe }); put("172.18.5.4", new byte[]{ (byte) 0xac, 0x12, 0x05, 0x04 }); put("0.0.0.0", new byte[]{ 0x00, 0x00, 0x00, 0x00 }); put("127.0.0.1", new byte[]{ 0x7f, 0x00, 0x00, 0x01 }); } }; private final static Map invalidIpV4Hosts = new HashMap() { private static final long serialVersionUID = 1299215199895717282L; { put("1.256.3.4", null); put("256.0.0.1", null); put("1.1.1.1.1", null); } }; private final static Map validIpV6Hosts = new HashMap() { private static final long serialVersionUID = 3999763170377573184L; { put("::ffff:5.6.7.8", new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, 0x05, 0x06, 0x07, 0x08} ); put("fdf8:f53b:82e4::53", new byte[]{ (byte) 0xfd, (byte) 0xf8, (byte) 0xf5, 0x3b, (byte) 0x82, (byte) 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53} ); put("fe80::200:5aee:feaa:20a2", new byte[]{ (byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5a, (byte) 0xee, (byte) 0xfe, (byte) 0xaa, 0x20, (byte) 0xa2} ); put("2001::1", new byte[]{ 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} ); put("2001:0000:4136:e378:8000:63bf:3fff:fdd2", new byte[]{ 0x20, 0x01, 0x00, 0x00, 0x41, 0x36, (byte) 0xe3, 0x78, (byte) 0x80, 0x00, 0x63, (byte) 0xbf, 0x3f, (byte) 0xff, (byte) 0xfd, (byte) 0xd2} ); put("2001:0002:6c::430", new byte[]{ 0x20, 0x01, 0x00, 0x02, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x30} ); put("2001:10:240:ab::a", new byte[]{ 0x20, 0x01, 0x00, 0x10, 0x02, 0x40, 0x00, (byte) 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a}); put("2002:cb0a:3cdd:1::1", new byte[]{ 0x20, 0x02, (byte) 0xcb, 0x0a, 0x3c, (byte) 0xdd, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} ); put("2001:db8:8:4::2", new byte[]{ 0x20, 0x01, 0x0d, (byte) 0xb8, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} ); put("ff01:0:0:0:0:0:0:2", new byte[]{ (byte) 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} ); put("[fdf8:f53b:82e4::53]", new byte[]{ (byte) 0xfd, (byte) 0xf8, (byte) 0xf5, 0x3b, (byte) 0x82, (byte) 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53} ); put("[fe80::200:5aee:feaa:20a2]", new byte[]{ (byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5a, (byte) 0xee, (byte) 0xfe, (byte) 0xaa, 0x20, (byte) 0xa2} ); put("[2001::1]", new byte[]{ 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} ); put("[2001:0000:4136:e378:8000:63bf:3fff:fdd2]", new byte[]{ 0x20, 0x01, 0x00, 0x00, 0x41, 0x36, (byte) 0xe3, 0x78, (byte) 0x80, 0x00, 0x63, (byte) 0xbf, 0x3f, (byte) 0xff, (byte) 0xfd, (byte) 0xd2} ); put("0:1:2:3:4:5:6:789a", new byte[]{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x78, (byte) 0x9a} ); put("0:1:2:3::f", new byte[]{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f} ); put("0:0:0:0:0:0:10.0.0.1", new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01} ); put("::ffff:192.168.0.1", new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xc0, (byte) 0xa8, 0x00, 0x01} ); } }; private final static Map invalidIpV6Hosts = new HashMap() { private static final long serialVersionUID = -5870810805409009696L; { // Test method with garbage. put("Obvious Garbage", null); // Test method with preferred style, too many : put("0:1:2:3:4:5:6:7:8", null); // Test method with preferred style, not enough : put("0:1:2:3:4:5:6", null); // Test method with preferred style, bad digits. put("0:1:2:3:4:5:6:x", null); // Test method with preferred style, adjacent : put("0:1:2:3:4:5:6::7", null); // Test method with preferred style, too many digits. put("0:1:2:3:4:5:6:789abcdef", null); // Test method with compressed style, bad digits. put("0:1:2:3::x", null); // Test method with compressed style, too many adjacent : put("0:1:2:::3", null); // Test method with compressed style, too many digits. put("0:1:2:3::abcde", null); // Test method with preferred style, too many : put("0:1:2:3:4:5:6:7:8", null); // Test method with compressed style, not enough : put("0:1", null); // Test method with ipv4 style, bad ipv6 digits. put("0:0:0:0:0:x:10.0.0.1", null); // Test method with ipv4 style, bad ipv4 digits. put("0:0:0:0:0:0:10.0.0.x", null); // Test method with ipv4 style, adjacent : put("0:0:0:0:0::0:10.0.0.1", null); // Test method with ipv4 style, too many ipv6 digits. put("0:0:0:0:0:00000:10.0.0.1", null); // Test method with ipv4 style, too many : put("0:0:0:0:0:0:0:10.0.0.1", null); // Test method with ipv4 style, not enough : put("0:0:0:0:0:10.0.0.1", null); // Test method with ipv4 style, too many . put("0:0:0:0:0:0:10.0.0.0.1", null); // Test method with ipv4 style, not enough . put("0:0:0:0:0:0:10.0.1", null); // Test method with ipv4 style, adjacent . put("0:0:0:0:0:0:10..0.0.1", null); // Test method with compressed ipv4 style, bad ipv6 digits. put("::fffx:192.168.0.1", null); // Test method with compressed ipv4 style, bad ipv4 digits. put("::ffff:192.168.0.x", null); // Test method with compressed ipv4 style, too many adjacent : put(":::ffff:192.168.0.1", null); // Test method with compressed ipv4 style, too many ipv6 digits. put("::fffff:192.168.0.1", null); // Test method with compressed ipv4 style, too many ipv4 digits. put("::ffff:1923.168.0.1", null); // Test method with compressed ipv4 style, not enough : put(":ffff:192.168.0.1", null); // Test method with compressed ipv4 style, too many . put("::ffff:192.168.0.1.2", null); // Test method with compressed ipv4 style, not enough . put("::ffff:192.168.0", null); // Test method with compressed ipv4 style, adjacent . put("::ffff:192.168..0.1", null); // Test method, garbage. put("absolute, and utter garbage", null); // Test method, bad ipv6 digits. put("x:0:0:0:0:0:10.0.0.1", null); // Test method, bad ipv4 digits. put("0:0:0:0:0:0:x.0.0.1", null); // Test method, too many ipv6 digits. put("00000:0:0:0:0:0:10.0.0.1", null); // Test method, too many ipv4 digits. put("0:0:0:0:0:0:10.0.0.1000", null); // Test method, too many : put("0:0:0:0:0:0:0:10.0.0.1", null); // Test method, not enough : put("0:0:0:0:0:10.0.0.1", null); // Test method, too many . put("0:0:0:0:0:0:10.0.0.0.1", null); // Test method, not enough . put("0:0:0:0:0:0:10.0.1", null); // Test method, adjacent . put("0:0:0:0:0:0:10.0.0..1", null); } }; @Test public void testIsValidIpV4Address() { for (String host : validIpV4Hosts.keySet()) { assertTrue(NetUtil.isValidIpV4Address(host)); } for (String host : invalidIpV4Hosts.keySet()) { assertFalse(NetUtil.isValidIpV4Address(host)); } } @Test public void testIsValidIpV6Address() { for (String host : validIpV6Hosts.keySet()) { assertTrue(NetUtil.isValidIpV6Address(host)); } for (String host : invalidIpV6Hosts.keySet()) { assertFalse(NetUtil.isValidIpV6Address(host)); } } @Test public void testCreateByteArrayFromIpAddressString() { for (Entry stringEntry : validIpV4Hosts.entrySet()) { assertArrayEquals(stringEntry.getValue(), NetUtil.createByteArrayFromIpAddressString(stringEntry.getKey())); } for (Entry stringEntry : invalidIpV4Hosts.entrySet()) { assertArrayEquals(stringEntry.getValue(), NetUtil.createByteArrayFromIpAddressString(stringEntry.getKey())); } for (Entry stringEntry : validIpV6Hosts.entrySet()) { assertArrayEquals(stringEntry.getValue(), NetUtil.createByteArrayFromIpAddressString(stringEntry.getKey())); } for (Entry stringEntry : invalidIpV6Hosts.entrySet()) { assertArrayEquals(stringEntry.getValue(), NetUtil.createByteArrayFromIpAddressString(stringEntry.getKey())); } } }netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/TestUtil.java000066400000000000000000000114021225554127700262250ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.junit.Ignore; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** */ @Ignore public final class TestUtil { private static final InetAddress LOCALHOST; static { InetAddress localhost; try { localhost = InetAddress.getLocalHost(); validateHost(localhost); } catch (IOException e) { // The default local host names did not work. Try hard-coded IPv4 address. try { localhost = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }); validateHost(localhost); } catch (IOException e1) { // The hard-coded IPv4 address did not work. Try hard coded IPv6 address. try { localhost = InetAddress.getByAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }); validateHost(localhost); } catch (IOException e2) { throw new Error("Failed to resolve localhost - incorrect network configuration?", e2); } } } LOCALHOST = localhost; } private static void validateHost(InetAddress host) throws IOException { ServerSocket ss = null; Socket s1 = null; Socket s2 = null; try { ss = new ServerSocket(); ss.setReuseAddress(false); ss.bind(new InetSocketAddress(host, 0)); s1 = new Socket(host, ss.getLocalPort()); s2 = ss.accept(); } finally { if (s2 != null) { try { s2.close(); } catch (IOException e) { // Ignore } } if (s1 != null) { try { s1.close(); } catch (IOException e) { // Ignore } } if (ss != null) { try { ss.close(); } catch (IOException e) { // Ignore } } } } public static InetAddress getLocalHost() { // We cache this because some machine takes almost forever to return // from InetAddress.getLocalHost(). I think it's due to the incorrect // /etc/hosts or /etc/resolve.conf. return LOCALHOST; } private static final int START_PORT = 32768; private static final int END_PORT = 65536; private static final int NUM_CANDIDATES = END_PORT - START_PORT; private static final List PORTS = new ArrayList(); private static Iterator portIterator; static { for (int i = START_PORT; i < END_PORT; i ++) { PORTS.add(i); } Collections.shuffle(PORTS); } private static int nextCandidatePort() { if (portIterator == null || !portIterator.hasNext()) { portIterator = PORTS.iterator(); } return portIterator.next(); } /** * Return a free port which can be used to bind to * * @return port */ public static int getFreePort() { for (int i = 0; i < NUM_CANDIDATES; i ++) { int port = nextCandidatePort(); try { // Ensure it is possible to bind on both wildcard and loopback. ServerSocket ss; ss = new ServerSocket(); ss.setReuseAddress(false); ss.bind(new InetSocketAddress(port)); ss.close(); ss = new ServerSocket(); ss.setReuseAddress(false); ss.bind(new InetSocketAddress(LOCALHOST, port)); ss.close(); return port; } catch (IOException e) { // ignore } } throw new RuntimeException("unable to find a free port"); } private TestUtil() { // Unused } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/ThreadRenamingRunnableTest.java000066400000000000000000000127511225554127700316770ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import org.junit.After; import org.junit.AfterClass; import org.junit.Test; import java.security.Permission; import java.util.concurrent.Executor; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; public class ThreadRenamingRunnableTest { @After public void setUp() { ThreadRenamingRunnable.setThreadNameDeterminer(ThreadNameDeterminer.PROPOSED); } @Test public void defaultIsProposed() { assertSame(ThreadNameDeterminer.PROPOSED, ThreadRenamingRunnable.getThreadNameDeterminer()); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullName() throws Exception { new ThreadRenamingRunnable(createMock(Runnable.class), null); } @Test(expected = NullPointerException.class) public void shouldNotAllowNullRunnable() throws Exception { new ThreadRenamingRunnable(null, "foo"); } @Test public void testWithoutSecurityManager() throws Exception { final String oldThreadName = Thread.currentThread().getName(); Executor e = new ImmediateExecutor(); e.execute(new ThreadRenamingRunnable( new Runnable() { public void run() { assertEquals("foo", Thread.currentThread().getName()); assertFalse(oldThreadName.equals(Thread.currentThread().getName())); } }, "foo")); assertEquals(oldThreadName, Thread.currentThread().getName()); } @Test public void testWithSecurityManager() throws Exception { final String oldThreadName = Thread.currentThread().getName(); Executor e = new ImmediateExecutor(); System.setSecurityManager(new SecurityManager() { @Override public void checkAccess(Thread t) { throw new SecurityException(); } @Override public void checkPermission(Permission perm, Object context) { // Allow } @Override public void checkPermission(Permission perm) { // Allow } }); try { e.execute(new ThreadRenamingRunnable( new Runnable() { public void run() { assertEquals(oldThreadName, Thread.currentThread().getName()); } }, "foo")); } finally { System.setSecurityManager(null); assertEquals(oldThreadName, Thread.currentThread().getName()); } } // Tests mainly changed which were introduced as part of #711 @Test public void testThreadNameDeterminer() { final String oldThreadName = Thread.currentThread().getName(); final String newThreadName = "new"; final String proposed = "proposed"; ThreadNameDeterminer determiner = new ThreadNameDeterminer() { public String determineThreadName(String currentThreadName, String proposedThreadName) throws Exception { assertEquals(proposed, proposedThreadName); assertEquals(oldThreadName, currentThreadName); return newThreadName; } }; ThreadRenamingRunnable.setThreadNameDeterminer(new ThreadNameDeterminer() { public String determineThreadName(String currentThreadName, String proposedThreadName) throws Exception { assertEquals(proposed, proposedThreadName); assertEquals(oldThreadName, currentThreadName); return proposed; } }); Executor e = new ImmediateExecutor(); try { e.execute(new ThreadRenamingRunnable(new Runnable() { public void run() { assertEquals("Should use the given ThreadNameDEterminer", newThreadName, Thread.currentThread().getName()); } }, proposed, determiner)); } finally { assertEquals(oldThreadName, Thread.currentThread().getName()); } try { e.execute(new ThreadRenamingRunnable(new Runnable() { public void run() { assertEquals("Should use the static set ThreadNameDeterminer", proposed, Thread.currentThread().getName()); } }, proposed)); } finally { assertEquals(oldThreadName, Thread.currentThread().getName()); } } @AfterClass public static void after() { // reset to default ThreadRenamingRunnable.setThreadNameDeterminer(ThreadNameDeterminer.PROPOSED); } private static class ImmediateExecutor implements Executor { ImmediateExecutor() { } public void execute(Runnable command) { command.run(); } } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/VirtualExecutorServiceTest.java000066400000000000000000000036721225554127700320100ustar00rootroot00000000000000/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util; import static junit.framework.Assert.*; import org.junit.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class VirtualExecutorServiceTest { // https://github.com/netty/netty/issues/906 @Test public void awaitTerminationTest() throws InterruptedException { final CountDownLatch started = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1); Runnable task = new Runnable() { public void run() { try { started.countDown(); latch.await(); } catch (InterruptedException e) { // ignore } } }; ExecutorService executorService = Executors.newCachedThreadPool(); VirtualExecutorService virtualExecutorService = new VirtualExecutorService(executorService); virtualExecutorService.execute(task); started.await(); virtualExecutorService.shutdown(); assertFalse(virtualExecutorService.awaitTermination(1, TimeUnit.SECONDS)); latch.countDown(); assertTrue(virtualExecutorService.awaitTermination(1, TimeUnit.SECONDS)); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/internal/000077500000000000000000000000001225554127700254235ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/internal/ConversionUtilTest.java000066400000000000000000000045741225554127700321230ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import static org.junit.Assert.*; import org.junit.Test; public class ConversionUtilTest { @Test public void testNumberToInt() { assertEquals(42, ConversionUtil.toInt(Long.valueOf(42))); } @Test public void testStringToInt() { assertEquals(42, ConversionUtil.toInt("42")); } @Test public void testBooleanToBoolean() { assertTrue(ConversionUtil.toBoolean(Boolean.TRUE)); assertFalse(ConversionUtil.toBoolean(Boolean.FALSE)); } @Test public void testNumberToBoolean() { assertTrue(ConversionUtil.toBoolean(Integer.valueOf(42))); assertFalse(ConversionUtil.toBoolean(Integer.valueOf(0))); } @Test public void testStringToBoolean() { assertTrue(ConversionUtil.toBoolean("y")); assertTrue(ConversionUtil.toBoolean("Y")); assertTrue(ConversionUtil.toBoolean("yes")); assertTrue(ConversionUtil.toBoolean("YES")); assertTrue(ConversionUtil.toBoolean("yeah")); assertTrue(ConversionUtil.toBoolean("YEAH")); assertTrue(ConversionUtil.toBoolean("t")); assertTrue(ConversionUtil.toBoolean("T")); assertTrue(ConversionUtil.toBoolean("true")); assertTrue(ConversionUtil.toBoolean("TRUE")); assertTrue(ConversionUtil.toBoolean("42")); assertFalse(ConversionUtil.toBoolean("")); assertFalse(ConversionUtil.toBoolean("n")); assertFalse(ConversionUtil.toBoolean("no")); assertFalse(ConversionUtil.toBoolean("NO")); assertFalse(ConversionUtil.toBoolean("f")); assertFalse(ConversionUtil.toBoolean("false")); assertFalse(ConversionUtil.toBoolean("FALSE")); assertFalse(ConversionUtil.toBoolean("0")); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/internal/StackTraceSimplifierTest.java000066400000000000000000000113451225554127700332020ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.DefaultChannelPipeline; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.util.ThreadRenamingRunnable; import org.junit.Test; public class StackTraceSimplifierTest { @Test public void testBasicSimplification() { Exception e = new Exception(); e.setStackTrace(new StackTraceElement[] { new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1), new StackTraceElement("com.example.Foo", "b", null, 1), new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), new StackTraceElement(ThreadRenamingRunnable.class.getName(), "d", null, 1), }); StackTraceSimplifier.simplify(e); StackTraceElement[] simplified = e.getStackTrace(); assertEquals(2, simplified.length); assertEquals(ChannelBuffer.class.getName(), simplified[0].getClassName()); assertEquals("com.example.Foo", simplified[1].getClassName()); } @Test public void testNestedSimplification() { Exception e1 = new Exception(); e1.setStackTrace(new StackTraceElement[] { new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1), new StackTraceElement("com.example.Foo", "b", null, 1), new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), new StackTraceElement(DefaultChannelPipeline.class.getName(), "d", null, 1), new StackTraceElement(ThreadRenamingRunnable.class.getName(), "e", null, 1), }); Exception e2 = new Exception(e1); e2.setStackTrace(new StackTraceElement[] { new StackTraceElement(Channel.class.getName(), "a", null, 1), new StackTraceElement("com.example.Bar", "b", null, 1), new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), new StackTraceElement(DefaultChannelPipeline.class.getName(), "d", null, 1), new StackTraceElement(ThreadRenamingRunnable.class.getName(), "e", null, 1), }); StackTraceSimplifier.simplify(e2); StackTraceElement[] simplified1 = e1.getStackTrace(); assertEquals(2, simplified1.length); assertEquals(ChannelBuffer.class.getName(), simplified1[0].getClassName()); assertEquals("com.example.Foo", simplified1[1].getClassName()); StackTraceElement[] simplified2 = e2.getStackTrace(); assertEquals(2, simplified2.length); assertEquals(Channel.class.getName(), simplified2[0].getClassName()); assertEquals("com.example.Bar", simplified2[1].getClassName()); } @Test public void testNettyBugDetection() { Exception e = new Exception(); e.setStackTrace(new StackTraceElement[] { new StackTraceElement(DefaultChannelPipeline.class.getName(), "a", null, 1), new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1), new StackTraceElement("com.example.Foo", "b", null, 1), new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), new StackTraceElement(ThreadRenamingRunnable.class.getName(), "d", null, 1), }); StackTraceSimplifier.simplify(e); StackTraceElement[] simplified = e.getStackTrace(); assertEquals(5, simplified.length); } @Test public void testEmptyStackTrace() { Exception e = new Exception(); e.setStackTrace(new StackTraceElement[0]); StackTraceSimplifier.simplify(e); assertEquals(0, e.getStackTrace().length); } @Test public void testNullStackTrace() { Exception e = createNiceMock(Exception.class); expect(e.getStackTrace()).andReturn(null).anyTimes(); replay(e); StackTraceSimplifier.simplify(e); assertNull(e.getStackTrace()); verify(e); } } netty-netty-3.9.0.Final/src/test/java/org/jboss/netty/util/internal/StringUtilTest.java000066400000000000000000000064751225554127700312460ustar00rootroot00000000000000/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.util.internal; import org.junit.Test; import static org.junit.Assert.*; /** * Unit test for {@link StringUtil}. */ public class StringUtilTest { @Test public void stripControlCharactersObjectNull() { assertNull(StringUtil.stripControlCharacters(null)); } @Test public void stripControlCharactersNull() { assertNull(StringUtil.stripControlCharacters(null)); } @Test public void stripControlCharactersRightTrim() { final char controlCode = 0x0000; final String object = "abbb" + controlCode; assertEquals(5, object.length()); final String stripped = StringUtil.stripControlCharacters(object); assertFalse(object.equals(stripped)); assertEquals(4, stripped.length()); } @Test public void stripControlCharactersLeftTrim() { final char controlCode = 0x0000; final String string = controlCode + "abbb"; assertEquals(5, string.length()); final String stripped = StringUtil.stripControlCharacters(string); assertFalse(string.equals(stripped)); assertEquals(4, stripped.length()); } @Test public void stripControlCharacters() { for (char i = 0x0000; i <= 0x001F; i ++) { assertStripped(i); } for (char i = 0x007F; i <= 0x009F; i ++) { assertStripped(i); } } private static void assertStripped(final char controlCode) { final Object object = "aaa" + controlCode + "bbb"; final String stripped = StringUtil.stripControlCharacters(object); assertEquals("aaa bbb", stripped); } @Test public void stripNonControlCharacter() { final char controlCode = 0x002F; final String string = controlCode + "abbb"; final String stripped = StringUtil.stripControlCharacters(string); assertEquals("The string should be unchanged", string, stripped); } @Test public void splitSimple() { assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo:bar", ':')); } @Test public void splitWithTrailingDelimiter() { assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo,bar,", ',')); } @Test public void splitWithTrailingDelimiters() { assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo!bar!!", '!')); } @Test public void splitWithConsecutiveDelimiters() { assertArrayEquals(new String[] { "foo", "", "bar" }, StringUtil.split("foo$$bar", '$')); } @Test public void splitWithDelimiterAtBeginning() { assertArrayEquals(new String[] { "", "foo", "bar" }, StringUtil.split("#foo#bar", '#')); } } netty-netty-3.9.0.Final/src/test/resources/000077500000000000000000000000001225554127700206515ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/resources/websocketx/000077500000000000000000000000001225554127700230275ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/resources/websocketx/html5/000077500000000000000000000000001225554127700240605ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/resources/websocketx/html5/css/000077500000000000000000000000001225554127700246505ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/resources/websocketx/html5/css/socket.css000066400000000000000000000000611225554127700266470ustar00rootroot00000000000000textarea { width: 500px; height: 300px; }netty-netty-3.9.0.Final/src/test/resources/websocketx/html5/js/000077500000000000000000000000001225554127700244745ustar00rootroot00000000000000netty-netty-3.9.0.Final/src/test/resources/websocketx/html5/js/socket.js000066400000000000000000000022741225554127700263270ustar00rootroot00000000000000(function() { var Sock = function() { var socket; if (!window.WebSocket) { window.WebSocket = window.MozWebSocket; } if (window.WebSocket) { socket = new WebSocket("ws://localhost:8080/websocket"); socket.onopen = onopen; socket.onmessage = onmessage; socket.onclose = onclose; } else { alert("Your browser does not support Web Socket."); } function onopen(event) { getTextAreaElement().value = "Web Socket opened!"; } function onmessage(event) { appendTextArea(event.data); } function onclose(event) { appendTextArea("Web Socket closed"); } function appendTextArea(newData) { var el = getTextAreaElement(); el.value = el.value + '\n' + newData; } function getTextAreaElement() { return document.getElementById('responseText'); } function send(event) { event.preventDefault(); if (window.WebSocket) { if (socket.readyState == WebSocket.OPEN) { socket.send(event.target.message.value); } else { alert("The socket is not open."); } } } document.forms.inputform.addEventListener('submit', send, false); } window.addEventListener('load', function() { new Sock(); }, false); })(); netty-netty-3.9.0.Final/src/test/resources/websocketx/html5/websocket.html000066400000000000000000000011231225554127700267310ustar00rootroot00000000000000 Web Socket Example

Enter a message

Repsonse from Server