diff --git a/org.eclipse.jgit.http.server/.classpath b/org.eclipse.jgit.http.server/.classpath new file mode 100644 index 000000000..304e86186 --- /dev/null +++ b/org.eclipse.jgit.http.server/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.eclipse.jgit.http.server/.fbprefs b/org.eclipse.jgit.http.server/.fbprefs new file mode 100644 index 000000000..81a0767ff --- /dev/null +++ b/org.eclipse.jgit.http.server/.fbprefs @@ -0,0 +1,125 @@ +#FindBugs User Preferences +#Mon May 04 16:24:13 PDT 2009 +detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true +detectorBadAppletConstructor=BadAppletConstructor|false +detectorBadResultSetAccess=BadResultSetAccess|true +detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true +detectorBadUseOfReturnValue=BadUseOfReturnValue|true +detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true +detectorBooleanReturnNull=BooleanReturnNull|true +detectorCallToUnsupportedMethod=CallToUnsupportedMethod|true +detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true +detectorCheckTypeQualifiers=CheckTypeQualifiers|true +detectorCloneIdiom=CloneIdiom|false +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 +detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true +detectorFinalizerNullsFields=FinalizerNullsFields|true +detectorFindBadCast2=FindBadCast2|true +detectorFindBadForLoop=FindBadForLoop|true +detectorFindCircularDependencies=FindCircularDependencies|false +detectorFindDeadLocalStores=FindDeadLocalStores|true +detectorFindDoubleCheck=FindDoubleCheck|true +detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true +detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true +detectorFindFinalizeInvocations=FindFinalizeInvocations|true +detectorFindFloatEquality=FindFloatEquality|true +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|false +detectorInefficientToArray=InefficientToArray|true +detectorInfiniteLoop=InfiniteLoop|true +detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true +detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|false +detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true +detectorInitializationChain=InitializationChain|true +detectorInstantiateStaticClass=InstantiateStaticClass|true +detectorInvalidJUnitTest=InvalidJUnitTest|true +detectorIteratorIdioms=IteratorIdioms|true +detectorLazyInit=LazyInit|true +detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true +detectorMethodReturnCheck=MethodReturnCheck|true +detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true +detectorMutableLock=MutableLock|true +detectorMutableStaticFields=MutableStaticFields|true +detectorNaming=Naming|true +detectorNumberConstructor=NumberConstructor|true +detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true +detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true +detectorPublicSemaphores=PublicSemaphores|false +detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true +detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true +detectorRedundantInterfaces=RedundantInterfaces|true +detectorRepeatedConditionals=RepeatedConditionals|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 +detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true +detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true +detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true +detectorURLProblems=URLProblems|true +detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true +detectorUnnecessaryMath=UnnecessaryMath|true +detectorUnreadFields=UnreadFields|true +detectorUseObjectEquals=UseObjectEquals|false +detectorUselessSubclassMethod=UselessSubclassMethod|false +detectorVarArgsProblems=VarArgsProblems|true +detectorVolatileUsage=VolatileUsage|true +detectorWaitInLoop=WaitInLoop|true +detectorWrongMapIterator=WrongMapIterator|true +detectorXMLFactoryBypass=XMLFactoryBypass|true +detector_threshold=2 +effort=default +excludefilter0=findBugs/FindBugsExcludeFilter.xml +filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,MT_CORRECTNESS,PERFORMANCE,STYLE|false +filter_settings_neg=MALICIOUS_CODE,NOISE,I18N,SECURITY,EXPERIMENTAL| +run_at_full_build=true diff --git a/org.eclipse.jgit.http.server/.gitignore b/org.eclipse.jgit.http.server/.gitignore new file mode 100644 index 000000000..934e0e06f --- /dev/null +++ b/org.eclipse.jgit.http.server/.gitignore @@ -0,0 +1,2 @@ +/bin +/target diff --git a/org.eclipse.jgit.http.server/.project b/org.eclipse.jgit.http.server/.project new file mode 100644 index 000000000..24bd8442e --- /dev/null +++ b/org.eclipse.jgit.http.server/.project @@ -0,0 +1,28 @@ + + + org.eclipse.jgit.http.server + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..66ac15c47 --- /dev/null +++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Mon Aug 11 16:46:12 PDT 2008 +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 000000000..006e07ede --- /dev/null +++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,3 @@ +#Mon Mar 24 18:55:50 EDT 2008 +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..76557139e --- /dev/null +++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,334 @@ +#Fri Oct 02 18:43:47 PDT 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=error +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=error +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=error +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=error +org.eclipse.jdt.core.compiler.problem.unusedLocal=error +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error +org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=1 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=80 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..02fa3390b --- /dev/null +++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,61 @@ +#Wed Jan 06 12:13:14 PST 2010 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_JGit Format +formatter_settings_version=11 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=false +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=false +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF new file mode 100644 index 000000000..92b02e876 --- /dev/null +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %plugin_name +Bundle-SymbolicName: org.eclipse.jgit.http.server +Bundle-Version: 0.6.0.qualifier +Bundle-Localization: plugin +Bundle-Vendor: %provider_name +Export-Package: + org.eclipse.jgit.http.server;version="0.6.0", + org.eclipse.jgit.http.server.glue;version="0.6.0", + org.eclipse.jgit.http.server.resolver;version="0.6.0" +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Import-Package: javax.servlet;version="[2.5.0,3.0.0)", + javax.servlet.http;version="[2.5.0,3.0.0)", + org.eclipse.jgit.errors;version="0.6.0", + org.eclipse.jgit.lib;version="0.6.0", + org.eclipse.jgit.revwalk;version="0.6.0", + org.eclipse.jgit.transport;version="0.6.0", + org.eclipse.jgit.util;version="0.6.0", + org.eclipse.jgit.util.io;version="0.6.0" diff --git a/org.eclipse.jgit.http.server/build.properties b/org.eclipse.jgit.http.server/build.properties new file mode 100644 index 000000000..aa1a00826 --- /dev/null +++ b/org.eclipse.jgit.http.server/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties diff --git a/org.eclipse.jgit.http.server/plugin.properties b/org.eclipse.jgit.http.server/plugin.properties new file mode 100644 index 000000000..6ca52145a --- /dev/null +++ b/org.eclipse.jgit.http.server/plugin.properties @@ -0,0 +1,2 @@ +plugin_name=Java Git HTTP Server (Incubation) +provider_name=eclipse.org diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml new file mode 100644 index 000000000..cb49402ae --- /dev/null +++ b/org.eclipse.jgit.http.server/pom.xml @@ -0,0 +1,101 @@ + + + + + 4.0.0 + + + org.eclipse.jgit + org.eclipse.jgit-parent + 0.6.0-SNAPSHOT + + + org.eclipse.jgit.http.server + JGit - HTTP Server + + + Git aware HTTP server implementation. + + + + + org.eclipse.jgit + org.eclipse.jgit + ${project.version} + + + + javax.servlet + servlet-api + provided + + + + + src/ + + + + . + + plugin.properties + + + + + + + maven-jar-plugin + + + META-INF/MANIFEST.MF + + + + + + diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java new file mode 100644 index 000000000..810f69420 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; +import static org.eclipse.jgit.http.server.ServletUtils.getRepository; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.http.server.resolver.AsIsFileService; +import org.eclipse.jgit.http.server.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException; +import org.eclipse.jgit.lib.Repository; + +class AsIsFileFilter implements Filter { + private final AsIsFileService asIs; + + AsIsFileFilter(final AsIsFileService getAnyFile) { + this.asIs = getAnyFile; + } + + public void init(FilterConfig config) throws ServletException { + // Do nothing. + } + + public void destroy() { + // Do nothing. + } + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + try { + final Repository db = getRepository(request); + asIs.access((HttpServletRequest) request, db); + chain.doFilter(request, response); + } catch (ServiceNotAuthorizedException e) { + ((HttpServletResponse) response).sendError(SC_UNAUTHORIZED); + } catch (ServiceNotEnabledException e) { + ((HttpServletResponse) response).sendError(SC_FORBIDDEN); + } + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java new file mode 100644 index 000000000..280450d01 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT; +import static javax.servlet.http.HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE; +import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_RANGES; +import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_LENGTH; +import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_RANGE; +import static org.eclipse.jgit.util.HttpSupport.HDR_IF_RANGE; +import static org.eclipse.jgit.util.HttpSupport.HDR_RANGE; + +import java.io.EOFException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.util.Enumeration; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.util.IO; + +/** + * Dumps a file over HTTP GET (or its information via HEAD). + *

+ * Supports a single byte range requested via {@code Range} HTTP header. This + * feature supports a dumb client to resume download of a larger object file. + */ +final class FileSender { + private final File path; + + private final RandomAccessFile source; + + private final long lastModified; + + private final long fileLen; + + private long pos; + + private long end; + + FileSender(final File path) throws FileNotFoundException { + this.path = path; + this.source = new RandomAccessFile(path, "r"); + + try { + this.lastModified = path.lastModified(); + this.fileLen = source.getChannel().size(); + this.end = fileLen; + } catch (IOException e) { + try { + source.close(); + } catch (IOException closeError) { + // Ignore any error closing the stream. + } + + final FileNotFoundException r; + r = new FileNotFoundException("Cannot get length of " + path); + r.initCause(e); + throw r; + } + } + + void close() { + try { + source.close(); + } catch (IOException e) { + // Ignore close errors on a read-only stream. + } + } + + long getLastModified() { + return lastModified; + } + + String getTailChecksum() throws IOException { + final int n = 20; + final byte[] buf = new byte[n]; + IO.readFully(source.getChannel(), fileLen - n, buf, 0, n); + return ObjectId.fromRaw(buf).getName(); + } + + void serve(final HttpServletRequest req, final HttpServletResponse rsp, + final boolean sendBody) throws IOException { + if (!initRangeRequest(req, rsp)) { + rsp.sendError(SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return; + } + + rsp.setHeader(HDR_ACCEPT_RANGES, "bytes"); + rsp.setHeader(HDR_CONTENT_LENGTH, Long.toString(end - pos)); + + if (sendBody) { + final OutputStream out = rsp.getOutputStream(); + try { + final byte[] buf = new byte[4096]; + while (pos < end) { + final int r = (int) Math.min(buf.length, end - pos); + final int n = source.read(buf, 0, r); + if (n < 0) { + throw new EOFException("Unexpected EOF on " + path); + } + out.write(buf, 0, n); + pos += n; + } + out.flush(); + } finally { + out.close(); + } + } + } + + private boolean initRangeRequest(final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + final Enumeration rangeHeaders = getRange(req); + if (!rangeHeaders.hasMoreElements()) { + // No range headers, the request is fine. + return true; + } + + final String range = rangeHeaders.nextElement(); + if (rangeHeaders.hasMoreElements()) { + // To simplify the code we support only one range. + return false; + } + + final int eq = range.indexOf('='); + final int dash = range.indexOf('-'); + if (eq < 0 || dash < 0 || !range.startsWith("bytes=")) { + return false; + } + + final String ifRange = req.getHeader(HDR_IF_RANGE); + if (ifRange != null && !getTailChecksum().equals(ifRange)) { + // If the client asked us to verify the ETag and its not + // what they expected we need to send the entire content. + return true; + } + + try { + if (eq + 1 == dash) { + // "bytes=-500" means last 500 bytes + pos = Long.parseLong(range.substring(dash + 1)); + pos = fileLen - pos; + } else { + // "bytes=500-" (position 500 to end) + // "bytes=500-1000" (position 500 to 1000) + pos = Long.parseLong(range.substring(eq + 1, dash)); + if (dash < range.length() - 1) { + end = Long.parseLong(range.substring(dash + 1)); + end++; // range was inclusive, want exclusive + } + } + } catch (NumberFormatException e) { + // We probably hit here because of a non-digit such as + // "," appearing at the end of the first range telling + // us there is a second range following. To simplify + // the code we support only one range. + return false; + } + + if (end > fileLen) { + end = fileLen; + } + if (pos >= end) { + return false; + } + + rsp.setStatus(SC_PARTIAL_CONTENT); + rsp.setHeader(HDR_CONTENT_RANGE, "bytes " + pos + "-" + (end - 1) + "/" + + fileLen); + source.seek(pos); + return true; + } + + @SuppressWarnings("unchecked") + private static Enumeration getRange(final HttpServletRequest req) { + return req.getHeaders(HDR_RANGE); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java new file mode 100644 index 000000000..1ce2776e4 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import java.io.File; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; + +import org.eclipse.jgit.http.server.glue.MetaServlet; +import org.eclipse.jgit.http.server.glue.RegexGroupFilter; +import org.eclipse.jgit.http.server.glue.ServletBinder; +import org.eclipse.jgit.http.server.resolver.FileResolver; +import org.eclipse.jgit.http.server.resolver.AsIsFileService; +import org.eclipse.jgit.http.server.resolver.RepositoryResolver; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.util.StringUtils; + +/** + * Handles Git repository access over HTTP. + *

+ * Applications embedding this servlet should map a directory path within the + * application to this servlet, for example: + * + *

+ *   <servlet>
+ *     <servlet-name>GitServlet</servlet-name>
+ *     <servlet-class>org.eclipse.jgit.http.server.GitServlet</servlet-class>
+ *     <init-param>
+ *       <param-name>base-path</param-name>
+ *       <param-value>/var/srv/git</param-value>
+ *     </init-param>
+ *     <init-param>
+ *       <param-name>export-all</param-name>
+ *       <param-value>0</param-value>
+ *     </init-param>
+ * </servlet>
+ *   <servlet-mapping>
+ *     <servlet-name>GitServlet</servlet-name>
+ *     <url-pattern>/git/*</url-pattern>
+ *   </servlet-mapping>
+ * 
+ * + *

+ * Applications may wish to add additional repository action URLs to this + * servlet by taking advantage of its extension from {@link MetaServlet}. + * Callers may register their own URL suffix translations through + * {@link #serve(String)}, or their regex translations through + * {@link #serveRegex(String)}. Each translation should contain a complete + * filter pipeline which ends with the HttpServlet that should handle the + * requested action. + */ +public class GitServlet extends MetaServlet { + private static final long serialVersionUID = 1L; + + private volatile boolean initialized; + + private RepositoryResolver resolver; + + private AsIsFileService asIs = new AsIsFileService(); + + /** + * New servlet that will load its base directory from {@code web.xml}. + *

+ * The required parameter {@code base-path} must be configured to point to + * the local filesystem directory where all served Git repositories reside. + */ + public GitServlet() { + // Initialized above by field declarations. + } + + /** + * New servlet configured with a specific resolver. + * + * @param resolver + * the resolver to use when matching URL to Git repository. If + * null the {@code base-path} parameter will be looked for in the + * parameter table during init, which usually comes from the + * {@code web.xml} file of the web application. + */ + public void setRepositoryResolver(RepositoryResolver resolver) { + assertNotInitialized(); + this.resolver = resolver; + } + + /** + * @param f + * the filter to validate direct access to repository files + * through a dumb client. If {@code null} then dumb client + * support is completely disabled. + */ + public void setAsIsFileService(AsIsFileService f) { + assertNotInitialized(); + this.asIs = f != null ? f : AsIsFileService.DISABLED; + } + + private void assertNotInitialized() { + if (initialized) + throw new IllegalStateException("Already initialized by container"); + } + + @Override + public void init(final ServletConfig config) throws ServletException { + super.init(config); + + if (resolver == null) { + final File root = getFile("base-path"); + final boolean exportAll = getBoolean("export-all"); + setRepositoryResolver(new FileResolver(root, exportAll)); + } + + initialized = true; + + if (asIs != AsIsFileService.DISABLED) { + final IsLocalFilter mustBeLocal = new IsLocalFilter(); + final AsIsFileFilter enabled = new AsIsFileFilter(asIs); + + serve("*/" + Constants.INFO_REFS)// + .through(mustBeLocal)// + .through(enabled)// + .with(new InfoRefsServlet()); + + serve("*/" + Constants.HEAD)// + .through(mustBeLocal)// + .through(enabled)// + .with(new TextFileServlet(Constants.HEAD)); + + final String info_alternates = "objects/info/alternates"; + serve("*/" + info_alternates)// + .through(mustBeLocal)// + .through(enabled)// + .with(new TextFileServlet(info_alternates)); + + final String http_alternates = "objects/info/http-alternates"; + serve("*/" + http_alternates)// + .through(mustBeLocal)// + .through(enabled)// + .with(new TextFileServlet(http_alternates)); + + serve("*/objects/info/packs")// + .through(mustBeLocal)// + .through(enabled)// + .with(new InfoPacksServlet()); + + serveRegex("^/(.*)/objects/([0-9a-f]{2}/[0-9a-f]{38})$")// + .through(mustBeLocal)// + .through(enabled)// + .through(new RegexGroupFilter(2))// + .with(new ObjectFileServlet.Loose()); + + serveRegex("^/(.*)/objects/(pack/pack-[0-9a-f]{40}\\.pack)$")// + .through(mustBeLocal)// + .through(enabled)// + .through(new RegexGroupFilter(2))// + .with(new ObjectFileServlet.Pack()); + + serveRegex("^/(.*)/objects/(pack/pack-[0-9a-f]{40}\\.idx)$")// + .through(mustBeLocal)// + .through(enabled)// + .through(new RegexGroupFilter(2))// + .with(new ObjectFileServlet.PackIdx()); + } + } + + private File getFile(final String param) throws ServletException { + String n = getInitParameter(param); + if (n == null || "".equals(n)) + throw new ServletException("Parameter " + param + " not set"); + + File path = new File(n); + if (!path.exists()) + throw new ServletException(path + " (for " + param + ") not found"); + return path; + } + + private boolean getBoolean(String param) throws ServletException { + String n = getInitParameter(param); + if (n == null) + return false; + try { + return StringUtils.toBoolean(n); + } catch (IllegalArgumentException err) { + throw new ServletException("Invalid boolean " + param + " = " + n); + } + } + + @Override + protected ServletBinder register(ServletBinder binder) { + if (resolver == null) + throw new IllegalStateException("No resolver available"); + binder = binder.through(new NoCacheFilter()); + binder = binder.through(new RepositoryFilter(resolver)); + return binder; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java new file mode 100644 index 000000000..dff1e8252 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static org.eclipse.jgit.http.server.ServletUtils.getRepository; +import static org.eclipse.jgit.http.server.ServletUtils.sendPlainText; + +import java.io.IOException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.lib.ObjectDatabase; +import org.eclipse.jgit.lib.ObjectDirectory; +import org.eclipse.jgit.lib.PackFile; + +/** Sends the current list of pack files, sorted most recent first. */ +class InfoPacksServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + public void doGet(final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + sendPlainText(packList(req), req, rsp); + } + + private static String packList(final HttpServletRequest req) { + final StringBuilder out = new StringBuilder(); + final ObjectDatabase db = getRepository(req).getObjectDatabase(); + if (db instanceof ObjectDirectory) { + for (PackFile pack : ((ObjectDirectory) db).getPacks()) { + out.append("P "); + out.append(pack.getPackFile().getName()); + out.append('\n'); + } + } + out.append('\n'); + return out.toString(); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java new file mode 100644 index 000000000..7bad51717 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static org.eclipse.jgit.http.server.ServletUtils.getRepository; +import static org.eclipse.jgit.http.server.ServletUtils.send; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevFlag; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.RefAdvertiser; +import org.eclipse.jgit.util.HttpSupport; + +/** Send a complete list of current refs, including peeled values for tags. */ +class InfoRefsServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + public void doGet(final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + // Assume a dumb client and send back the dumb client + // version of the info/refs file. + final byte[] raw = dumbHttp(req); + rsp.setContentType(HttpSupport.TEXT_PLAIN); + rsp.setCharacterEncoding(Constants.CHARACTER_ENCODING); + send(raw, req, rsp); + } + + private byte[] dumbHttp(final HttpServletRequest req) throws IOException { + final Repository db = getRepository(req); + final RevWalk walk = new RevWalk(db); + final RevFlag ADVERTISED = walk.newFlag("ADVERTISED"); + final StringBuilder out = new StringBuilder(); + final RefAdvertiser adv = new RefAdvertiser() { + @Override + protected void writeOne(final CharSequence line) { + // Whoever decided that info/refs should use a different + // delimiter than the native git:// protocol shouldn't + // be allowed to design this sort of stuff. :-( + out.append(line.toString().replace(' ', '\t')); + } + + @Override + protected void end() { + // No end marker required for info/refs format. + } + }; + adv.init(walk, ADVERTISED); + adv.setDerefTags(true); + + Map refs = new HashMap(db.getAllRefs()); + refs.remove(Constants.HEAD); + adv.send(refs.values()); + return out.toString().getBytes(Constants.CHARACTER_ENCODING); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java new file mode 100644 index 000000000..34edf8279 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static org.eclipse.jgit.http.server.ServletUtils.getRepository; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.lib.ObjectDirectory; +import org.eclipse.jgit.lib.Repository; + +/** + * Requires the target {@link Repository} to be available via local filesystem. + *

+ * The target {@link Repository} must be using a {@link ObjectDirectory}, so the + * downstream servlet can directly access its contents on disk. + */ +class IsLocalFilter implements Filter { + public void init(FilterConfig config) throws ServletException { + // Do nothing. + } + + public void destroy() { + // Do nothing. + } + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + if (isLocal(getRepository(request))) + chain.doFilter(request, response); + else + ((HttpServletResponse) response).sendError(SC_FORBIDDEN); + } + + private static boolean isLocal(final Repository db) { + return db.getObjectDatabase() instanceof ObjectDirectory; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java new file mode 100644 index 000000000..6a23cb95f --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static org.eclipse.jgit.util.HttpSupport.HDR_CACHE_CONTROL; +import static org.eclipse.jgit.util.HttpSupport.HDR_EXPIRES; +import static org.eclipse.jgit.util.HttpSupport.HDR_PRAGMA; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +/** Adds HTTP response headers to prevent caching by proxies/browsers. */ +class NoCacheFilter implements Filter { + public void init(FilterConfig config) throws ServletException { + // Do nothing. + } + + public void destroy() { + // Do nothing. + } + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse rsp = (HttpServletResponse) response; + + rsp.setHeader(HDR_EXPIRES, "Fri, 01 Jan 1980 00:00:00 GMT"); + rsp.setHeader(HDR_PRAGMA, "no-cache"); + + final String nocache = "no-cache, max-age=0, must-revalidate"; + rsp.setHeader(HDR_CACHE_CONTROL, nocache); + + chain.doFilter(request, response); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java new file mode 100644 index 000000000..5d774a824 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; +import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED; +import static org.eclipse.jgit.http.server.ServletUtils.getRepository; +import static org.eclipse.jgit.util.HttpSupport.HDR_ETAG; +import static org.eclipse.jgit.util.HttpSupport.HDR_IF_MODIFIED_SINCE; +import static org.eclipse.jgit.util.HttpSupport.HDR_IF_NONE_MATCH; +import static org.eclipse.jgit.util.HttpSupport.HDR_LAST_MODIFIED; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.lib.ObjectDirectory; +import org.eclipse.jgit.lib.Repository; + +/** Sends any object from {@code GIT_DIR/objects/??/0 38}, or any pack file. */ +abstract class ObjectFileServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + static class Loose extends ObjectFileServlet { + private static final long serialVersionUID = 1L; + + Loose() { + super("application/x-git-loose-object"); + } + + @Override + String etag(final FileSender sender) throws IOException { + return Long.toHexString(sender.getLastModified()); + } + } + + private static abstract class PackData extends ObjectFileServlet { + private static final long serialVersionUID = 1L; + + PackData(String contentType) { + super(contentType); + } + + @Override + String etag(final FileSender sender) throws IOException { + return sender.getTailChecksum(); + } + } + + static class Pack extends PackData { + private static final long serialVersionUID = 1L; + + Pack() { + super("application/x-git-packed-objects"); + } + } + + static class PackIdx extends PackData { + private static final long serialVersionUID = 1L; + + PackIdx() { + super("application/x-git-packed-objects-toc"); + } + } + + private final String contentType; + + ObjectFileServlet(final String contentType) { + this.contentType = contentType; + } + + abstract String etag(FileSender sender) throws IOException; + + @Override + public void doGet(final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + serve(req, rsp, true); + } + + @Override + protected void doHead(final HttpServletRequest req, + final HttpServletResponse rsp) throws ServletException, IOException { + serve(req, rsp, false); + } + + private void serve(final HttpServletRequest req, + final HttpServletResponse rsp, final boolean sendBody) + throws IOException { + final File obj = new File(objects(req), req.getPathInfo()); + final FileSender sender; + try { + sender = new FileSender(obj); + } catch (FileNotFoundException e) { + rsp.sendError(SC_NOT_FOUND); + return; + } + + try { + final String etag = etag(sender); + final long lastModified = (sender.getLastModified() / 1000) * 1000; + + String ifNoneMatch = req.getHeader(HDR_IF_NONE_MATCH); + if (etag != null && etag.equals(ifNoneMatch)) { + rsp.sendError(SC_NOT_MODIFIED); + return; + } + + long ifModifiedSince = req.getDateHeader(HDR_IF_MODIFIED_SINCE); + if (0 < lastModified && lastModified < ifModifiedSince) { + rsp.sendError(SC_NOT_MODIFIED); + return; + } + + if (etag != null) + rsp.setHeader(HDR_ETAG, etag); + if (0 < lastModified) + rsp.setDateHeader(HDR_LAST_MODIFIED, lastModified); + rsp.setContentType(contentType); + sender.serve(req, rsp, sendBody); + } finally { + sender.close(); + } + } + + private static File objects(final HttpServletRequest req) { + final Repository db = getRepository(req); + return ((ObjectDirectory) db.getObjectDatabase()).getDirectory(); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java new file mode 100644 index 000000000..a212f0d7b --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; +import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; +import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_REPOSITORY; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.http.server.resolver.RepositoryResolver; +import org.eclipse.jgit.http.server.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException; +import org.eclipse.jgit.lib.Repository; + +/** + * Opens a repository named by the path info through {@link RepositoryResolver}. + *

+ * This filter assumes it is invoked by {@link GitServlet} and is likely to not + * work as expected if called from any other class. This filter assumes the path + * info of the current request is a repository name which can be used by the + * configured {@link RepositoryResolver} to open a {@link Repository} and attach + * it to the current request. + *

+ * This filter sets request attribute {@link ServletUtils#ATTRIBUTE_REPOSITORY} + * when it discovers the repository, and automatically closes and removes the + * attribute when the request is complete. + */ +public class RepositoryFilter implements Filter { + private final RepositoryResolver resolver; + + private ServletContext context; + + /** + * Create a new filter. + * + * @param resolver + * the resolver which will be used to translate the URL name + * component to the actual {@link Repository} instance for the + * current web request. + */ + public RepositoryFilter(final RepositoryResolver resolver) { + this.resolver = resolver; + } + + public void init(final FilterConfig config) throws ServletException { + context = config.getServletContext(); + } + + public void destroy() { + context = null; + } + + public void doFilter(final ServletRequest request, + final ServletResponse rsp, final FilterChain chain) + throws IOException, ServletException { + if (request.getAttribute(ATTRIBUTE_REPOSITORY) != null) { + context.log("Internal server error, request attribute " + + ATTRIBUTE_REPOSITORY + " was already set when " + + getClass().getName() + " was invoked."); + ((HttpServletResponse) rsp).sendError(SC_INTERNAL_SERVER_ERROR); + return; + } + + final HttpServletRequest req = (HttpServletRequest) request; + + String name = req.getPathInfo(); + if (name == null || name.length() == 0) { + ((HttpServletResponse) rsp).sendError(SC_NOT_FOUND); + return; + } + if (name.startsWith("/")) + name = name.substring(1); + + final Repository db; + try { + db = resolver.open(req, name); + } catch (RepositoryNotFoundException e) { + ((HttpServletResponse) rsp).sendError(SC_NOT_FOUND); + return; + } catch (ServiceNotAuthorizedException e) { + ((HttpServletResponse) rsp).sendError(SC_UNAUTHORIZED); + return; + } catch (ServiceNotEnabledException e) { + ((HttpServletResponse) rsp).sendError(SC_FORBIDDEN); + return; + } + try { + request.setAttribute(ATTRIBUTE_REPOSITORY, db); + chain.doFilter(request, rsp); + } finally { + request.removeAttribute(ATTRIBUTE_REPOSITORY); + db.close(); + } + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java new file mode 100644 index 000000000..d6b039246 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static org.eclipse.jgit.util.HttpSupport.ENCODING_GZIP; +import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT_ENCODING; +import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING; +import static org.eclipse.jgit.util.HttpSupport.HDR_ETAG; +import static org.eclipse.jgit.util.HttpSupport.TEXT_PLAIN; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.MessageDigest; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; + +/** Common utility functions for servlets. */ +public final class ServletUtils { + /** Request attribute which stores the {@link Repository} instance. */ + public static final String ATTRIBUTE_REPOSITORY = "org.eclipse.jgit.Repository"; + + /** + * Get the selected repository from the request. + * + * @param req + * the current request. + * @return the repository; never null. + * @throws IllegalStateException + * the repository was not set by the filter, the servlet is + * being invoked incorrectly and the programmer should ensure + * the filter runs before the servlet. + * @see #ATTRIBUTE_REPOSITORY + */ + public static Repository getRepository(final ServletRequest req) { + Repository db = (Repository) req.getAttribute(ATTRIBUTE_REPOSITORY); + if (db == null) + throw new IllegalStateException("Expected Repository attribute"); + return db; + } + + /** + * Open the request input stream, automatically inflating if necessary. + *

+ * This method automatically inflates the input stream if the request + * {@code Content-Encoding} header was set to {@code gzip} or the legacy + * {@code x-gzip}. + * + * @param req + * the incoming request whose input stream needs to be opened. + * @return an input stream to read the raw, uncompressed request body. + * @throws IOException + * if an input or output exception occurred. + */ + public static InputStream getInputStream(final HttpServletRequest req) + throws IOException { + InputStream in = req.getInputStream(); + final String enc = req.getHeader(HDR_CONTENT_ENCODING); + if (ENCODING_GZIP.equals(enc) || "x-gzip".equals(enc)) //$NON-NLS-1$ + in = new GZIPInputStream(in); + else if (enc != null) + throw new IOException(HDR_CONTENT_ENCODING + " \"" + enc + "\"" + + ": not supported by this library."); + return in; + } + + /** + * Send a plain text response to a {@code GET} or {@code HEAD} HTTP request. + *

+ * The text response is encoded in the Git character encoding, UTF-8. + *

+ * If the user agent supports a compressed transfer encoding and the content + * is large enough, the content may be compressed before sending. + *

+ * The {@code ETag} and {@code Content-Length} headers are automatically set + * by this method. {@code Content-Encoding} is conditionally set if the user + * agent supports a compressed transfer. Callers are responsible for setting + * any cache control headers. + * + * @param content + * to return to the user agent as this entity's body. + * @param req + * the incoming request. + * @param rsp + * the outgoing response. + * @throws IOException + * the servlet API rejected sending the body. + */ + public static void sendPlainText(final String content, + final HttpServletRequest req, final HttpServletResponse rsp) + throws IOException { + final byte[] raw = content.getBytes(Constants.CHARACTER_ENCODING); + rsp.setContentType(TEXT_PLAIN); + rsp.setCharacterEncoding(Constants.CHARACTER_ENCODING); + send(raw, req, rsp); + } + + /** + * Send a response to a {@code GET} or {@code HEAD} HTTP request. + *

+ * If the user agent supports a compressed transfer encoding and the content + * is large enough, the content may be compressed before sending. + *

+ * The {@code ETag} and {@code Content-Length} headers are automatically set + * by this method. {@code Content-Encoding} is conditionally set if the user + * agent supports a compressed transfer. Callers are responsible for setting + * {@code Content-Type} and any cache control headers. + * + * @param content + * to return to the user agent as this entity's body. + * @param req + * the incoming request. + * @param rsp + * the outgoing response. + * @throws IOException + * the servlet API rejected sending the body. + */ + public static void send(byte[] content, final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + content = sendInit(content, req, rsp); + final OutputStream out = rsp.getOutputStream(); + try { + out.write(content); + out.flush(); + } finally { + out.close(); + } + } + + private static byte[] sendInit(byte[] content, + final HttpServletRequest req, final HttpServletResponse rsp) + throws IOException { + rsp.setHeader(HDR_ETAG, etag(content)); + if (256 < content.length && acceptsGzipEncoding(req)) { + content = compress(content); + rsp.setHeader(HDR_CONTENT_ENCODING, ENCODING_GZIP); + } + rsp.setContentLength(content.length); + return content; + } + + private static boolean acceptsGzipEncoding(final HttpServletRequest req) { + final String accepts = req.getHeader(HDR_ACCEPT_ENCODING); + return accepts != null && 0 <= accepts.indexOf(ENCODING_GZIP); + } + + private static byte[] compress(final byte[] raw) throws IOException { + final int maxLen = raw.length + 32; + final ByteArrayOutputStream out = new ByteArrayOutputStream(maxLen); + final GZIPOutputStream gz = new GZIPOutputStream(out); + gz.write(raw); + gz.finish(); + gz.flush(); + return out.toByteArray(); + } + + private static String etag(final byte[] content) { + final MessageDigest md = Constants.newMessageDigest(); + md.update(content); + return ObjectId.fromRaw(md.digest()).getName(); + } + + private ServletUtils() { + // static utility class only + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java new file mode 100644 index 000000000..5bf5546cf --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server; + +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; +import static org.eclipse.jgit.http.server.ServletUtils.getRepository; +import static org.eclipse.jgit.http.server.ServletUtils.send; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.util.HttpSupport; +import org.eclipse.jgit.util.IO; + +/** Sends a small text meta file from the repository. */ +class TextFileServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + private final String fileName; + + TextFileServlet(final String name) { + this.fileName = name; + } + + public void doGet(final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + try { + rsp.setContentType(HttpSupport.TEXT_PLAIN); + send(read(req), req, rsp); + } catch (FileNotFoundException noFile) { + rsp.sendError(SC_NOT_FOUND); + } + } + + private byte[] read(final HttpServletRequest req) throws IOException { + final File gitdir = getRepository(req).getDirectory(); + return IO.readFully(new File(gitdir, fileName)); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java new file mode 100644 index 000000000..c0a9e0e60 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** Sends a fixed status code to the client. */ +public class ErrorServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + private final int status; + + /** + * Sends a specific status code. + * + * @param status + * the HTTP status code to always send. + */ + public ErrorServlet(final int status) { + this.status = status; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse rsp) + throws ServletException, IOException { + rsp.sendError(status); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java new file mode 100644 index 000000000..d289743ba --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; + +import java.io.IOException; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Generic container servlet to manage routing to different pipelines. + *

+ * Callers can create and configure a new processing pipeline by using one of + * the {@link #serve(String)} or {@link #serveRegex(String)} methods to allocate + * a binder for a particular URL pattern. + *

+ * Registered filters and servlets are initialized lazily, usually during the + * first request. Once initialized the bindings in this servlet cannot be + * modified without destroying the servlet and thereby destroying all registered + * filters and servlets. + */ +public class MetaServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + static final String REGEX_GROUPS = "org.eclipse.jgit.http.server.glue.MetaServlet.serveRegex"; + + private final List bindings; + + private volatile UrlPipeline[] pipelines; + + /** Empty servlet with no bindings. */ + public MetaServlet() { + this.bindings = new ArrayList(); + } + + /** + * Construct a binding for a specific path. + * + * @param path + * pattern to match. + * @return binder for the passed path. + */ + public ServletBinder serve(String path) { + if (path.startsWith("*")) + return register(new SuffixPipeline.Binder(path.substring(1))); + throw new IllegalArgumentException("\"" + path + "\" not supported"); + } + + /** + * Construct a binding for a regular expression. + * + * @param expression + * the regular expression to pattern match the URL against. + * @return binder for the passed expression. + */ + public ServletBinder serveRegex(String expression) { + return register(new RegexPipeline.Binder(expression)); + } + + public void destroy() { + if (pipelines != null) { + Set destroyed = newIdentitySet(); + for (UrlPipeline p : pipelines) + p.destroy(destroyed); + pipelines = null; + } + } + + private static Set newIdentitySet() { + final Map m = new IdentityHashMap(); + return new AbstractSet() { + @Override + public boolean add(Object o) { + return m.put(o, o) == null; + } + + @Override + public boolean contains(Object o) { + return m.keySet().contains(o); + } + + @Override + public Iterator iterator() { + return m.keySet().iterator(); + } + + @Override + public int size() { + return m.size(); + } + }; + } + + @Override + protected void service(final HttpServletRequest req, + final HttpServletResponse rsp) throws ServletException, IOException { + final UrlPipeline p = find(req); + if (p != null) + p.service(req, rsp); + else + rsp.sendError(SC_NOT_FOUND); + } + + private UrlPipeline find(final HttpServletRequest req) + throws ServletException { + for (UrlPipeline p : getPipelines()) + if (p.match(req)) + return p; + return null; + } + + private ServletBinder register(ServletBinderImpl b) { + synchronized (bindings) { + if (pipelines != null) + throw new IllegalStateException("Servlet already initialized"); + bindings.add(b); + } + return register((ServletBinder) b); + } + + /** + * Configure a newly created binder. + * + * @param b + * the newly created binder. + * @return binder for the caller, potentially after adding one or more + * filters into the pipeline. + */ + protected ServletBinder register(ServletBinder b) { + return b; + } + + private UrlPipeline[] getPipelines() throws ServletException { + UrlPipeline[] r = pipelines; + if (r == null) { + synchronized (bindings) { + r = pipelines; + if (r == null) { + r = createPipelines(); + pipelines = r; + } + } + } + return r; + } + + private UrlPipeline[] createPipelines() throws ServletException { + UrlPipeline[] array = new UrlPipeline[bindings.size()]; + + for (int i = 0; i < bindings.size(); i++) + array[i] = bindings.get(i).create(); + + Set inited = newIdentitySet(); + for (UrlPipeline p : array) + p.init(getServletContext(), inited); + return array; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java new file mode 100644 index 000000000..ed7b1cf69 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * Switch servlet path and path info to use another regex match group. + *

+ * This filter is meant to be installed in the middle of a pipeline created by + * {@link MetaServlet#serveRegex(String)}. The passed request's servlet path is + * updated to be all text up to the start of the designated capture group, and + * the path info is changed to the contents of the capture group. + **/ +public class RegexGroupFilter implements Filter { + private final int groupIdx; + + /** + * @param groupIdx + * capture group number, 1 through the number of groups. + */ + public RegexGroupFilter(final int groupIdx) { + if (groupIdx < 1) + throw new IllegalArgumentException("Invalid index: " + groupIdx); + this.groupIdx = groupIdx - 1; + } + + public void init(FilterConfig config) throws ServletException { + // Do nothing. + } + + public void destroy() { + // Do nothing. + } + + public void doFilter(final ServletRequest request, + final ServletResponse rsp, final FilterChain chain) + throws IOException, ServletException { + final WrappedRequest[] g = groupsFor(request); + if (groupIdx < g.length) + chain.doFilter(g[groupIdx], rsp); + else + throw new ServletException("Invalid regex group " + (groupIdx + 1)); + } + + private static WrappedRequest[] groupsFor(final ServletRequest r) { + return (WrappedRequest[]) r.getAttribute(MetaServlet.REGEX_GROUPS); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java new file mode 100644 index 000000000..635ff5493 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; +import static org.eclipse.jgit.http.server.glue.MetaServlet.REGEX_GROUPS; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.Filter; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Selects requests by matching the URI against a regular expression. + *

+ * The pattern is bound and matched against the path info of the servlet + * request, as this class assumes it is invoked by {@link MetaServlet}. + *

+ * If there are capture groups in the regular expression, the matched ranges of + * the capture groups are stored as an array of modified HttpServetRequests, + * into the request attribute {@link MetaServlet#REGEX_GROUPS}. + *

+ * Each servlet request has been altered to have its {@code getPathInfo()} + * method return the matched text of the corresponding capture group. A + * {@link RegexGroupFilter} can be applied in the pipeline to switch the current + * HttpServletRequest to reference a different capture group before running + * additional filters, or the final servlet. + *

+ * This class dispatches the remainder of the pipeline using the first capture + * group as the current request, making {@code RegexGroupFilter} required only + * to access capture groups beyond the first. + */ +class RegexPipeline extends UrlPipeline { + static class Binder extends ServletBinderImpl { + private final Pattern pattern; + + Binder(final String p) { + pattern = Pattern.compile(p); + } + + UrlPipeline create() { + return new RegexPipeline(pattern, getFilters(), getServlet()); + } + } + + private final Pattern pattern; + + RegexPipeline(final Pattern pattern, final Filter[] filters, + final HttpServlet servlet) { + super(filters, servlet); + this.pattern = pattern; + } + + boolean match(final HttpServletRequest req) { + final String pathInfo = req.getPathInfo(); + return pathInfo != null && pattern.matcher(pathInfo).matches(); + } + + @Override + void service(HttpServletRequest req, HttpServletResponse rsp) + throws ServletException, IOException { + final String reqInfo = req.getPathInfo(); + if (reqInfo == null) { + rsp.sendError(SC_NOT_FOUND); + return; + } + + final Matcher cur = pattern.matcher(reqInfo); + if (!cur.matches()) { + rsp.sendError(SC_NOT_FOUND); + return; + } + + final String reqPath = req.getServletPath(); + final Object old = req.getAttribute(REGEX_GROUPS); + try { + if (1 <= cur.groupCount()) { + // If there are groups extract every capture group and + // build a request for them so RegexGroupFilter can pick + // a different capture group later. Continue using the + // first capture group as the path info. + WrappedRequest groups[] = new WrappedRequest[cur.groupCount()]; + for (int groupId = 1; groupId <= cur.groupCount(); groupId++) { + final int s = cur.start(groupId); + final String path, info; + + path = reqPath + reqInfo.substring(0, s); + info = cur.group(groupId); + groups[groupId - 1] = new WrappedRequest(req, path, info); + } + req.setAttribute(REGEX_GROUPS, groups); + super.service(groups[0], rsp); + + } else { + // No capture groups were present, service the whole request. + final String path = reqPath + reqInfo; + final String info = null; + super.service(new WrappedRequest(req, path, info), rsp); + } + } finally { + if (old != null) + req.setAttribute(REGEX_GROUPS, old); + else + req.removeAttribute(REGEX_GROUPS); + } + } + + @Override + public String toString() { + return "Pipeline[regex: " + pattern + " ]"; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java new file mode 100644 index 000000000..9c3ed50d0 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import javax.servlet.Filter; +import javax.servlet.http.HttpServlet; + +/** Binds a servlet to a URL. */ +public interface ServletBinder { + /** + * @param filter + * the filter to trigger while processing the path. + * @return {@code this}. + */ + public ServletBinder through(Filter filter); + + /** + * @param servlet + * the servlet to execute on this path. + */ + public void with(HttpServlet servlet); +} \ No newline at end of file diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java new file mode 100644 index 000000000..d4cd445a1 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.Filter; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletResponse; + +abstract class ServletBinderImpl implements ServletBinder { + private final List filters; + + private HttpServlet httpServlet; + + ServletBinderImpl() { + this.filters = new ArrayList(); + } + + public ServletBinder through(Filter filter) { + if (filter == null) + throw new NullPointerException("filter must not be null"); + filters.add(filter); + return this; + } + + public void with(HttpServlet servlet) { + if (servlet == null) + throw new NullPointerException("servlet must not be null"); + if (httpServlet != null) + throw new IllegalStateException("servlet was already bound"); + httpServlet = servlet; + } + + /** @return the configured servlet, or singleton returning 404 if none. */ + protected HttpServlet getServlet() { + if (httpServlet != null) + return httpServlet; + else + return new ErrorServlet(HttpServletResponse.SC_NOT_FOUND); + } + + /** @return the configured filters; zero-length array if none. */ + protected Filter[] getFilters() { + return filters.toArray(new Filter[filters.size()]); + } + + /** @return the pipeline that matches and executes this chain. */ + abstract UrlPipeline create(); +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java new file mode 100644 index 000000000..b94201625 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Selects requests by matching the suffix of the URI. + *

+ * The suffix string is literally matched against the path info of the servlet + * request, as this class assumes it is invoked by {@link MetaServlet}. Suffix + * strings may include path components. Examples include {@code /info/refs}, or + * just simple extension matches like {@code .txt}. + *

+ * When dispatching to the rest of the pipeline the HttpServletRequest is + * modified so that {@code getPathInfo()} does not contain the suffix that + * caused this pipeline to be selected. + */ +class SuffixPipeline extends UrlPipeline { + static class Binder extends ServletBinderImpl { + private final String suffix; + + Binder(final String suffix) { + this.suffix = suffix; + } + + UrlPipeline create() { + return new SuffixPipeline(suffix, getFilters(), getServlet()); + } + } + + private final String suffix; + + private final int suffixLen; + + SuffixPipeline(final String suffix, final Filter[] filters, + final HttpServlet servlet) { + super(filters, servlet); + this.suffix = suffix; + this.suffixLen = suffix.length(); + } + + boolean match(final HttpServletRequest req) { + final String pathInfo = req.getPathInfo(); + return pathInfo != null && pathInfo.endsWith(suffix); + } + + @Override + void service(HttpServletRequest req, HttpServletResponse rsp) + throws ServletException, IOException { + String curInfo = req.getPathInfo(); + String newPath = req.getServletPath() + curInfo; + String newInfo = curInfo.substring(0, curInfo.length() - suffixLen); + super.service(new WrappedRequest(req, newPath, newInfo), rsp); + } + + @Override + public String toString() { + return "Pipeline[ *" + suffix + " ]"; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java new file mode 100644 index 000000000..2257966d6 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.NoSuchElementException; +import java.util.Set; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Encapsulates the entire serving stack for a single URL. + *

+ * Subclasses provide the implementation of {@link #match(HttpServletRequest)}, + * which is called by {@link MetaServlet} in registration order to determine the + * pipeline that will be used to handle a request. + *

+ * The very bottom of each pipeline is a single {@link HttpServlet} that will + * handle producing the response for this pipeline's URL. {@link Filter}s may + * also be registered and applied around the servlet's processing, to manage + * request attributes, set standard response headers, or completely override the + * response generation. + */ +abstract class UrlPipeline { + /** Filters to apply around {@link #servlet}; may be empty but never null. */ + private final Filter[] filters; + + /** Instance that must generate the response; never null. */ + private final HttpServlet servlet; + + UrlPipeline(final Filter[] filters, final HttpServlet servlet) { + this.filters = filters; + this.servlet = servlet; + } + + /** + * Initialize all contained filters and servlets. + * + * @param context + * the servlet container context our {@link MetaServlet} is + * running within. + * @param inited + * (input/output) the set of filters and servlets which + * have already been initialized within the container context. If + * those same instances appear in this pipeline they are not + * initialized a second time. Filters and servlets that are first + * initialized by this pipeline will be added to this set. + * @throws ServletException + * a filter or servlet is unable to initialize. + */ + void init(final ServletContext context, final Set inited) + throws ServletException { + for (Filter ref : filters) + initFilter(ref, context, inited); + initServlet(servlet, context, inited); + } + + private static void initFilter(final Filter ref, + final ServletContext context, final Set inited) + throws ServletException { + if (!inited.contains(ref)) { + ref.init(new FilterConfig() { + public String getInitParameter(String name) { + return null; + } + + public Enumeration getInitParameterNames() { + return new Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + throw new NoSuchElementException(); + } + }; + } + + public ServletContext getServletContext() { + return context; + } + + public String getFilterName() { + return ref.getClass().getName(); + } + }); + inited.add(ref); + } + } + + private static void initServlet(final HttpServlet ref, + final ServletContext context, final Set inited) + throws ServletException { + if (!inited.contains(ref)) { + ref.init(new ServletConfig() { + public String getInitParameter(String name) { + return null; + } + + public Enumeration getInitParameterNames() { + return new Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public String nextElement() { + throw new NoSuchElementException(); + } + }; + } + + public ServletContext getServletContext() { + return context; + } + + public String getServletName() { + return ref.getClass().getName(); + } + }); + inited.add(ref); + } + } + + /** + * Destroy all contained filters and servlets. + * + * @param destroyed + * (input/output) the set of filters and servlets which + * have already been destroyed within the container context. If + * those same instances appear in this pipeline they are not + * destroyed a second time. Filters and servlets that are first + * destroyed by this pipeline will be added to this set. + */ + void destroy(final Set destroyed) { + for (Filter ref : filters) + destroyFilter(ref, destroyed); + destroyServlet(servlet, destroyed); + } + + private static void destroyFilter(Filter ref, Set destroyed) { + if (!destroyed.contains(ref)) { + ref.destroy(); + destroyed.add(ref); + } + } + + private static void destroyServlet(HttpServlet ref, Set destroyed) { + if (!destroyed.contains(ref)) { + ref.destroy(); + destroyed.add(ref); + } + } + + /** + * Determine if this pipeline handles the request's URL. + *

+ * This method should match on the request's {@code getPathInfo()} method, + * as {@link MetaServlet} passes the request along as-is to each pipeline's + * match method. + * + * @param req + * current HTTP request being considered by {@link MetaServlet}. + * @return {@code true} if this pipeline is configured to handle the + * request; {@code false} otherwise. + */ + abstract boolean match(HttpServletRequest req); + + /** + * Execute the filters and the servlet on the request. + *

+ * Invoked by {@link MetaServlet} once {@link #match(HttpServletRequest)} + * has determined this pipeline is the correct pipeline to handle the + * current request. + * + * @param req + * current HTTP request. + * @param rsp + * current HTTP response. + * @throws ServletException + * request cannot be completed. + * @throws IOException + * IO error prevents the request from being completed. + */ + void service(HttpServletRequest req, HttpServletResponse rsp) + throws ServletException, IOException { + if (0 < filters.length) + new Chain(filters, servlet).doFilter(req, rsp); + else + servlet.service(req, rsp); + } + + private static class Chain implements FilterChain { + private final Filter[] filters; + + private final HttpServlet servlet; + + private int filterIdx; + + Chain(final Filter[] filters, final HttpServlet servlet) { + this.filters = filters; + this.servlet = servlet; + } + + public void doFilter(ServletRequest req, ServletResponse rsp) + throws IOException, ServletException { + if (filterIdx < filters.length) + filters[filterIdx++].doFilter(req, rsp, this); + else + servlet.service(req, rsp); + } + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java new file mode 100644 index 000000000..7f8da7c44 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.glue; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +/** Overrides the path and path info. */ +public class WrappedRequest extends HttpServletRequestWrapper { + private final String path; + + private final String pathInfo; + + /** + * Create a new request with different path and path info properties. + * + * @param originalRequest + * the original HTTP request. + * @param path + * new servlet path to report to callers. + * @param pathInfo + * new path info to report to callers. + */ + public WrappedRequest(final HttpServletRequest originalRequest, + final String path, final String pathInfo) { + super(originalRequest); + this.path = path; + this.pathInfo = pathInfo; + } + + @Override + public String getPathTranslated() { + final String p = getPathInfo(); + return p != null ? getRealPath(p) : null; + } + + @Override + public String getPathInfo() { + return pathInfo; + } + + @Override + public String getServletPath() { + return path; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java new file mode 100644 index 000000000..b9545f910 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.resolver; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jgit.http.server.GitServlet; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.Config.SectionParser; + +/** + * Controls access to bare files in a repository. + *

+ * Older HTTP clients which do not speak the smart HTTP variant of the Git + * protocol fetch from a repository by directly getting its objects and pack + * files. This class, along with the {@code http.getanyfile} per-repository + * configuration setting, can be used by {@link GitServlet} to control whether + * or not these older clients are permitted to read these direct files. + */ +public class AsIsFileService { + /** Always throws {@link ServiceNotEnabledException}. */ + public static final AsIsFileService DISABLED = new AsIsFileService() { + @Override + public void access(HttpServletRequest req, Repository db) + throws ServiceNotEnabledException { + throw new ServiceNotEnabledException(); + } + }; + + private static final SectionParser CONFIG = new SectionParser() { + public ServiceConfig parse(final Config cfg) { + return new ServiceConfig(cfg); + } + }; + + private static class ServiceConfig { + final boolean enabled; + + ServiceConfig(final Config cfg) { + enabled = cfg.getBoolean("http", "getanyfile", true); + } + } + + /** + * Determine if {@code http.getanyfile} is enabled in the configuration. + * + * @param db + * the repository to check. + * @return {@code false} if {@code http.getanyfile} was explicitly set to + * {@code false} in the repository's configuration file; otherwise + * {@code true}. + */ + protected static boolean isEnabled(Repository db) { + return db.getConfig().get(CONFIG).enabled; + } + + /** + * Determine if access to any bare file of the repository is allowed. + *

+ * This method silently succeeds if the request is allowed, or fails by + * throwing a checked exception if access should be denied. + *

+ * The default implementation of this method checks {@code http.getanyfile}, + * throwing {@link ServiceNotEnabledException} if it was explicitly set to + * {@code false}, and otherwise succeeding silently. + * + * @param req + * current HTTP request, in case information from the request may + * help determine the access request. + * @param db + * the repository the request would obtain a bare file from. + * @throws ServiceNotEnabledException + * bare file access is not allowed on the target repository, by + * any user, for any reason. + * @throws ServiceNotAuthorizedException + * bare file access is not allowed for this HTTP request and + * repository, such as due to a permission error. + */ + public void access(HttpServletRequest req, Repository db) + throws ServiceNotEnabledException, ServiceNotAuthorizedException { + if (!isEnabled(db)) + throw new ServiceNotEnabledException(); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java new file mode 100644 index 000000000..82a0ce84a --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.resolver; + +import java.io.File; +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.lib.RepositoryCache.FileKey; + +/** Default resolver serving from a single root path in local filesystem. */ +public class FileResolver implements RepositoryResolver { + private final File basePath; + + private final boolean exportAll; + + /** + * Create a new resolver for the given path. + * + * @param basePath + * the base path all repositories are rooted under. + * @param exportAll + * if true, exports all repositories, ignoring the check for the + * {@code git-daemon-export-ok} files. + */ + public FileResolver(final File basePath, final boolean exportAll) { + this.basePath = basePath; + this.exportAll = exportAll; + } + + public Repository open(final HttpServletRequest req, + final String repositoryName) throws RepositoryNotFoundException, + ServiceNotEnabledException { + if (isUnreasonableName(repositoryName)) + throw new RepositoryNotFoundException(repositoryName); + + final Repository db; + try { + final File gitdir = new File(basePath, repositoryName); + db = RepositoryCache.open(FileKey.lenient(gitdir), true); + } catch (IOException e) { + throw new RepositoryNotFoundException(repositoryName, e); + } + + try { + if (isExportOk(req, repositoryName, db)) { + // We have to leak the open count to the caller, they + // are responsible for closing the repository if we + // complete successfully. + return db; + } else + throw new ServiceNotEnabledException(); + + } catch (RuntimeException e) { + db.close(); + throw new RepositoryNotFoundException(repositoryName, e); + + } catch (IOException e) { + db.close(); + throw new RepositoryNotFoundException(repositoryName, e); + + } catch (ServiceNotEnabledException e) { + db.close(); + throw e; + } + } + + /** @return {@code true} if all repositories are to be exported. */ + protected boolean isExportAll() { + return exportAll; + } + + /** + * Check if this repository can be served over HTTP. + *

+ * The default implementation of this method returns true only if either + * {@link #isExportAll()} is true, or the {@code git-daemon-export-ok} file + * is present in the repository's directory. + * + * @param req + * the current HTTP request. + * @param repositoryName + * name of the repository, as present in the URL. + * @param db + * the opened repository instance. + * @return true if the repository is accessible; false if not. + * @throws IOException + * the repository could not be accessed, the caller will claim + * the repository does not exist. + */ + protected boolean isExportOk(HttpServletRequest req, String repositoryName, + Repository db) throws IOException { + if (isExportAll()) + return true; + else + return new File(db.getDirectory(), "git-daemon-export-ok").exists(); + } + + private static boolean isUnreasonableName(final String name) { + if (name.length() == 0) + return true; // no empty paths + + if (name.indexOf('\\') >= 0) + return true; // no windows/dos style paths + if (new File(name).isAbsolute()) + return true; // no absolute paths + + if (name.startsWith("../")) + return true; // no "l../etc/passwd" + if (name.contains("/../")) + return true; // no "foo/../etc/passwd" + if (name.contains("/./")) + return true; // "foo/./foo" is insane to ask + if (name.contains("//")) + return true; // double slashes is sloppy, don't use it + + return false; // is a reasonable name + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/RepositoryResolver.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/RepositoryResolver.java new file mode 100644 index 000000000..ba17dac45 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/RepositoryResolver.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.resolver; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.lib.Repository; + +/** Locate a Git {@link Repository} by name from the URL. */ +public interface RepositoryResolver { + /** + * Locate and open a reference to a {@link Repository}. + *

+ * The caller is responsible for closing the returned Repository. + * + * @param req + * the current HTTP request, may be used to inspect session state + * including cookies or user authentication. + * @param name + * name of the repository, as parsed out of the URL. + * @return the opened repository instance, never null. + * @throws RepositoryNotFoundException + * the repository does not exist or the name is incorrectly + * formatted as a repository name. + * @throws ServiceNotAuthorizedException + * the repository exists, but HTTP access is not allowed for the + * current user. + * @throws ServiceNotEnabledException + * the repository exists, but HTTP access is not allowed on the + * target repository, by any user. + */ + Repository open(HttpServletRequest req, String name) + throws RepositoryNotFoundException, ServiceNotAuthorizedException, + ServiceNotEnabledException; +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotAuthorizedException.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotAuthorizedException.java new file mode 100644 index 000000000..fca044a10 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotAuthorizedException.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.resolver; + +/** Indicates the request service is not authorized for current user. */ +public class ServiceNotAuthorizedException extends Exception { + private static final long serialVersionUID = 1L; + + /** Indicates the request service is not available. */ + public ServiceNotAuthorizedException() { + super("Service not permitted"); + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotEnabledException.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotEnabledException.java new file mode 100644 index 000000000..dedc0d482 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotEnabledException.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * 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 Eclipse Foundation, 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. + */ + +package org.eclipse.jgit.http.server.resolver; + +/** Indicates the request service is not enabled on a repository. */ +public class ServiceNotEnabledException extends Exception { + private static final long serialVersionUID = 1L; + + /** Indicates the request service is not available. */ + public ServiceNotEnabledException() { + super("Service not enabled"); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java index d947a2cdc..c745e7326 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, Google Inc. + * Copyright (C) 2009-2010, Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -59,6 +59,18 @@ public class RepositoryNotFoundException extends TransportException { this(location.getPath()); } + /** + * Constructs an exception indicating a local repository does not exist. + * + * @param location + * description of the repository not found, usually file path. + * @param why + * why the repository does not exist. + */ + public RepositoryNotFoundException(final File location, Throwable why) { + this(location.getPath(), why); + } + /** * Constructs an exception indicating a local repository does not exist. * @@ -66,6 +78,22 @@ public class RepositoryNotFoundException extends TransportException { * description of the repository not found, usually file path. */ public RepositoryNotFoundException(final String location) { - super("repository not found: " + location); + super(message(location)); + } + + /** + * Constructs an exception indicating a local repository does not exist. + * + * @param location + * description of the repository not found, usually file path. + * @param why + * why the repository does not exist. + */ + public RepositoryNotFoundException(String location, Throwable why) { + super(message(location), why); + } + + private static String message(final String location) { + return "repository not found: " + location; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index b6b9c5e05..661371ca2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2009, Constantine Plotnikov * Copyright (C) 2007, Dave Watson - * Copyright (C) 2008-2009, Google Inc. + * Copyright (C) 2008-2010, Google Inc. * Copyright (C) 2009, Google, Inc. * Copyright (C) 2009, JetBrains s.r.o. * Copyright (C) 2007-2008, Robin Rosenberg @@ -298,20 +298,11 @@ public class Config { String n = getRawString(section, subsection, name); if (n == null) return defaultValue; - - if (MAGIC_EMPTY_VALUE == n || StringUtils.equalsIgnoreCase("yes", n) - || StringUtils.equalsIgnoreCase("true", n) - || StringUtils.equalsIgnoreCase("1", n) - || StringUtils.equalsIgnoreCase("on", n)) { + if (MAGIC_EMPTY_VALUE == n) return true; - - } else if (StringUtils.equalsIgnoreCase("no", n) - || StringUtils.equalsIgnoreCase("false", n) - || StringUtils.equalsIgnoreCase("0", n) - || StringUtils.equalsIgnoreCase("off", n)) { - return false; - - } else { + try { + return StringUtils.toBoolean(n); + } catch (IllegalArgumentException err) { throw new IllegalArgumentException("Invalid boolean value: " + section + "." + name + "=" + n); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java index 3910c8bd7..8ce2ff06e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010, Google Inc. * Copyright (C) 2008, Shawn O. Pearce * and other copyright owners as documented in the project's IP log. * @@ -55,6 +56,63 @@ import java.net.URLEncoder; /** Extra utilities to support usage of HTTP. */ public class HttpSupport { + /** The {@code POST} HTTP method. */ + public static final String METHOD_POST = "POST"; + + /** The {@code Cache-Control} header. */ + public static final String HDR_CACHE_CONTROL = "Cache-Control"; + + /** The {@code Pragma} header. */ + public static final String HDR_PRAGMA = "Pragma"; + + /** The {@code Date} header. */ + public static final String HDR_DATE = "Date"; + + /** The {@code Expires} header. */ + public static final String HDR_EXPIRES = "Expires"; + + /** The {@code ETag} header. */ + public static final String HDR_ETAG = "ETag"; + + /** The {@code If-None-Match} header. */ + public static final String HDR_IF_NONE_MATCH = "If-None-Match"; + + /** The {@code Last-Modified} header. */ + public static final String HDR_LAST_MODIFIED = "Last-Modified"; + + /** The {@code If-Modified-Since} header. */ + public static final String HDR_IF_MODIFIED_SINCE = "If-Modified-Since"; + + /** The {@code Content-Type} header. */ + public static final String HDR_CONTENT_TYPE = "Content-Type"; + + /** The {@code Content-Length} header. */ + public static final String HDR_CONTENT_LENGTH = "Content-Length"; + + /** The {@code Content-Encoding} header. */ + public static final String HDR_CONTENT_ENCODING = "Content-Encoding"; + + /** The {@code Content-Range} header. */ + public static final String HDR_CONTENT_RANGE = "Content-Range"; + + /** The {@code Accept-Ranges} header. */ + public static final String HDR_ACCEPT_RANGES = "Accept-Ranges"; + + /** The {@code If-Range} header. */ + public static final String HDR_IF_RANGE = "If-Range"; + + /** The {@code Range} header. */ + public static final String HDR_RANGE = "Range"; + + /** The {@code Accept-Encoding} header. */ + public static final String HDR_ACCEPT_ENCODING = "Accept-Encoding"; + + /** The {@code gzip} encoding value for {@link #HDR_ACCEPT_ENCODING}. */ + public static final String ENCODING_GZIP = "gzip"; + + /** The standard {@code text/plain} MIME type. */ + public static final String TEXT_PLAIN = "text/plain"; + /** * URL encode a value string into an output buffer. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java index ddde48d6c..582dce8af 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java @@ -115,6 +115,45 @@ public final class StringUtils { return true; } + /** + * Parse a string as a standard Git boolean value. + *

+ * The terms {@code yes}, {@code true}, {@code 1}, {@code on} can all be + * used to mean {@code true}. + *

+ * The terms {@code no}, {@code false}, {@code 0}, {@code off} can all be + * used to mean {@code false}. + *

+ * Comparisons ignore case, via {@link #equalsIgnoreCase(String, String)}. + * + * @param stringValue + * the string to parse. + * @return the boolean interpretation of {@code value}. + * @throws IllegalArgumentException + * if {@code value} is not recognized as one of the standard + * boolean names. + */ + public static boolean toBoolean(final String stringValue) { + if (stringValue == null) + throw new NullPointerException("Expected boolean string value"); + + if (equalsIgnoreCase("yes", stringValue) + || equalsIgnoreCase("true", stringValue) + || equalsIgnoreCase("1", stringValue) + || equalsIgnoreCase("on", stringValue)) { + return true; + + } else if (equalsIgnoreCase("no", stringValue) + || equalsIgnoreCase("false", stringValue) + || equalsIgnoreCase("0", stringValue) + || equalsIgnoreCase("off", stringValue)) { + return false; + + } else { + throw new IllegalArgumentException("Not a boolean: " + stringValue); + } + } + private StringUtils() { // Do not create instances } diff --git a/pom.xml b/pom.xml index a5887288c..d3467204f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@