summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.http.server/.classpath7
-rw-r--r--org.eclipse.jgit.http.server/.fbprefs125
-rw-r--r--org.eclipse.jgit.http.server/.gitignore2
-rw-r--r--org.eclipse.jgit.http.server/.project28
-rw-r--r--org.eclipse.jgit.http.server/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--org.eclipse.jgit.http.server/.settings/org.eclipse.core.runtime.prefs3
-rw-r--r--org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs334
-rw-r--r--org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.ui.prefs61
-rw-r--r--org.eclipse.jgit.http.server/META-INF/MANIFEST.MF21
-rw-r--r--org.eclipse.jgit.http.server/build.properties5
-rw-r--r--org.eclipse.jgit.http.server/plugin.properties2
-rw-r--r--org.eclipse.jgit.http.server/pom.xml101
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/AsIsFileFilter.java93
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java225
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java236
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java81
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java106
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/IsLocalFilter.java88
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/NoCacheFilter.java82
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ObjectFileServlet.java175
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/RepositoryFilter.java150
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java216
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/TextFileServlet.java85
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ErrorServlet.java74
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/MetaServlet.java210
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexGroupFilter.java97
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/RegexPipeline.java158
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinder.java63
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java92
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/SuffixPipeline.java108
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/UrlPipeline.java264
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/WrappedRequest.java87
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/AsIsFileService.java126
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java164
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/RepositoryResolver.java77
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotAuthorizedException.java54
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/ServiceNotEnabledException.java54
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/errors/RepositoryNotFoundException.java32
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java19
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java58
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java39
-rw-r--r--pom.xml12
42 files changed, 4000 insertions, 17 deletions
diff --git a/org.eclipse.jgit.http.server/.classpath b/org.eclipse.jgit.http.server/.classpath
new file mode 100644
index 0000000000..304e86186a
--- /dev/null
+++ b/org.eclipse.jgit.http.server/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jgit.http.server/.fbprefs b/org.eclipse.jgit.http.server/.fbprefs
new file mode 100644
index 0000000000..81a0767ff6
--- /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 0000000000..934e0e06ff
--- /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 0000000000..24bd8442e9
--- /dev/null
+++ b/org.eclipse.jgit.http.server/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.jgit.http.server</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
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 0000000000..66ac15c47c
--- /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/<project>=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 0000000000..006e07ede5
--- /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 0000000000..76557139ec
--- /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 0000000000..02fa3390be
--- /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=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><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 0000000000..92b02e8765
--- /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 0000000000..aa1a008269
--- /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 0000000000..6ca52145a7
--- /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 0000000000..cb49402ae5
--- /dev/null
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2009-2010, Google Inc.
+ Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit-parent</artifactId>
+ <version>0.6.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.eclipse.jgit.http.server</artifactId>
+ <name>JGit - HTTP Server</name>
+
+ <description>
+ Git aware HTTP server implementation.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src/</sourceDirectory>
+
+ <resources>
+ <resource>
+ <directory>.</directory>
+ <includes>
+ <include>plugin.properties</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
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 0000000000..810f694202
--- /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 0000000000..280450d01a
--- /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).
+ * <p>
+ * 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<String> 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<String> 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 0000000000..1ce2776e4d
--- /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.
+ * <p>
+ * Applications embedding this servlet should map a directory path within the
+ * application to this servlet, for example:
+ *
+ * <pre>
+ * &lt;servlet&gt;
+ * &lt;servlet-name&gt;GitServlet&lt;/servlet-name&gt;
+ * &lt;servlet-class&gt;org.eclipse.jgit.http.server.GitServlet&lt;/servlet-class&gt;
+ * &lt;init-param&gt;
+ * &lt;param-name&gt;base-path&lt;/param-name&gt;
+ * &lt;param-value&gt;/var/srv/git&lt;/param-value&gt;
+ * &lt;/init-param&gt;
+ * &lt;init-param&gt;
+ * &lt;param-name&gt;export-all&lt;/param-name&gt;
+ * &lt;param-value&gt;0&lt;/param-value&gt;
+ * &lt;/init-param&gt;
+ * &lt;/servlet&gt;
+ * &lt;servlet-mapping&gt;
+ * &lt;servlet-name&gt;GitServlet&lt;/servlet-name&gt;
+ * &lt;url-pattern&gt;/git/*&lt;/url-pattern&gt;
+ * &lt;/servlet-mapping&gt;
+ * </pre>
+ *
+ * <p>
+ * 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}.
+ * <p>
+ * 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 0000000000..dff1e8252e
--- /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 0000000000..7bad517170
--- /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<String, Ref> refs = new HashMap<String, Ref>(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 0000000000..34edf82792
--- /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.
+ * <p>
+ * 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 0000000000..6a23cb95f5
--- /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 0000000000..5d774a8248
--- /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 0000000000..a212f0d7ba
--- /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}.
+ * <p>
+ * 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.
+ * <p>
+ * 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 0000000000..d6b039246f
--- /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.
+ * <p>
+ * 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.
+ * <p>
+ * The text response is encoded in the Git character encoding, UTF-8.
+ * <p>
+ * If the user agent supports a compressed transfer encoding and the content
+ * is large enough, the content may be compressed before sending.
+ * <p>
+ * 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.
+ * <p>
+ * If the user agent supports a compressed transfer encoding and the content
+ * is large enough, the content may be compressed before sending.
+ * <p>
+ * 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 0000000000..5bf5546cf7
--- /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 0000000000..c0a9e0e608
--- /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 0000000000..d289743ba4
--- /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.
+ * <p>
+ * 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.
+ * <p>
+ * 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<ServletBinderImpl> bindings;
+
+ private volatile UrlPipeline[] pipelines;
+
+ /** Empty servlet with no bindings. */
+ public MetaServlet() {
+ this.bindings = new ArrayList<ServletBinderImpl>();
+ }
+
+ /**
+ * 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<Object> destroyed = newIdentitySet();
+ for (UrlPipeline p : pipelines)
+ p.destroy(destroyed);
+ pipelines = null;
+ }
+ }
+
+ private static Set<Object> newIdentitySet() {
+ final Map<Object, Object> m = new IdentityHashMap<Object, Object>();
+ return new AbstractSet<Object>() {
+ @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<Object> 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<Object> 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 0000000000..ed7b1cf694
--- /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.
+ * <p>
+ * 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 0000000000..635ff5493f
--- /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.
+ * <p>
+ * The pattern is bound and matched against the path info of the servlet
+ * request, as this class assumes it is invoked by {@link MetaServlet}.
+ * <p>
+ * 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}.
+ * <p>
+ * 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.
+ * <p>
+ * 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 0000000000..9c3ed50d08
--- /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 0000000000..d4cd445a13
--- /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<Filter> filters;
+
+ private HttpServlet httpServlet;
+
+ ServletBinderImpl() {
+ this.filters = new ArrayList<Filter>();
+ }
+
+ 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 0000000000..b942016259
--- /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.
+ * <p>
+ * 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}.
+ * <p>
+ * 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 0000000000..2257966d69
--- /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.
+ * <p>
+ * 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.
+ * <p>
+ * 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
+ * <i>(input/output)</i> 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<Object> 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<Object> inited)
+ throws ServletException {
+ if (!inited.contains(ref)) {
+ ref.init(new FilterConfig() {
+ public String getInitParameter(String name) {
+ return null;
+ }
+
+ public Enumeration getInitParameterNames() {
+ return new Enumeration<String>() {
+ 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<Object> inited)
+ throws ServletException {
+ if (!inited.contains(ref)) {
+ ref.init(new ServletConfig() {
+ public String getInitParameter(String name) {
+ return null;
+ }
+
+ public Enumeration getInitParameterNames() {
+ return new Enumeration<String>() {
+ 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
+ * <i>(input/output)</i> 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<Object> destroyed) {
+ for (Filter ref : filters)
+ destroyFilter(ref, destroyed);
+ destroyServlet(servlet, destroyed);
+ }
+
+ private static void destroyFilter(Filter ref, Set<Object> destroyed) {
+ if (!destroyed.contains(ref)) {
+ ref.destroy();
+ destroyed.add(ref);
+ }
+ }
+
+ private static void destroyServlet(HttpServlet ref, Set<Object> destroyed) {
+ if (!destroyed.contains(ref)) {
+ ref.destroy();
+ destroyed.add(ref);
+ }
+ }
+
+ /**
+ * Determine if this pipeline handles the request's URL.
+ * <p>
+ * 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.
+ * <p>
+ * 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 0000000000..7f8da7c440
--- /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 0000000000..b9545f9101
--- /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.
+ * <p>
+ * 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<ServiceConfig> CONFIG = new SectionParser<ServiceConfig>() {
+ 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.
+ * <p>
+ * This method silently succeeds if the request is allowed, or fails by
+ * throwing a checked exception if access should be denied.
+ * <p>
+ * 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 0000000000..82a0ce84a0
--- /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.
+ * <p>
+ * 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 0000000000..ba17dac45b
--- /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}.
+ * <p>
+ * 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 0000000000..fca044a10c
--- /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 0000000000..dedc0d4825
--- /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 d947a2cdc7..c745e7326e 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
@@ -64,8 +64,36 @@ public class RepositoryNotFoundException extends TransportException {
*
* @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.
+ *
+ * @param location
+ * 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 b6b9c5e05b..661371ca21 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 <constantine.plotnikov@gmail.com>
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
- * 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 <robin.rosenberg@dewire.com>
@@ -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 3910c8bd7f..8ce2ff06ec 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 <spearce@spearce.org>
* 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 ddde48d6cf..582dce8aff 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.
+ * <p>
+ * The terms {@code yes}, {@code true}, {@code 1}, {@code on} can all be
+ * used to mean {@code true}.
+ * <p>
+ * The terms {@code no}, {@code false}, {@code 0}, {@code off} can all be
+ * used to mean {@code false}.
+ * <p>
+ * 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 a5887288c9..d3467204f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- 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
@@ -135,6 +135,9 @@
<args4j-CQ>CQ 3454</args4j-CQ>
<args4j-version>2.0.12</args4j-version>
+
+ <servlet-api-CQ>CQ 3565</servlet-api-CQ>
+ <servlet-api-version>2.5</servlet-api-version>
</properties>
<build>
@@ -256,6 +259,12 @@
<artifactId>junit</artifactId>
<version>${junit-version}</version>
</dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>${servlet-api-version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -286,6 +295,7 @@
<modules>
<module>org.eclipse.jgit</module>
<module>org.eclipse.jgit.ui</module>
+ <module>org.eclipse.jgit.http.server</module>
<module>org.eclipse.jgit.pgm</module>
<module>org.eclipse.jgit.junit</module>
<module>org.eclipse.jgit.test</module>