Bug 558378: [R-Help] Fix accept header of R help server client request

  - Add utils to parse media type headers
  - Add check of accept header in API servlet

Change-Id: Ia0377ae82d2085b276be0a9f74a4c90a7bc2af29
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.classpath b/rhelp/org.eclipse.statet.rhelp.core-tests/.classpath
new file mode 100644
index 0000000..78c94b4
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.classpath
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="annotationpath" value="/org.eclipse.statet/eea/"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins">
+		<attributes>
+			<attribute name="annotationpath" value="/org.eclipse.statet/eea/"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.gitignore b/rhelp/org.eclipse.statet.rhelp.core-tests/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.project b/rhelp/org.eclipse.statet.rhelp.core-tests/.project
new file mode 100644
index 0000000..60da93d
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.statet.rhelp.core-tests</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.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.core.resources.prefs b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.core.runtime.prefs b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.jdt.core.prefs b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ea2d0f5
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,383 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=80
+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=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=32
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=49
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=80
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=80
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+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_relational_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=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.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=80
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=2
+org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_after_package=-2
+org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=-2
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=-2
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=-2
+org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
+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_lambda_body=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.align_tags_descriptions_grouped=false
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=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.count_line_length_from_starting_position=false
+org.eclipse.jdt.core.formatter.comment.format_block_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=false
+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=false
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+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.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=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=true
+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_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=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_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=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_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=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_bitwise_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=do not 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_switch_case_expressions=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_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not 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_try=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_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_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_try=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_switch_case_expressions=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_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=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_try=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_relational_operator=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_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=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.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
+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_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_after_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=-1
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=-1
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=-1
+org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=2
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+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.text_block_indentation=0
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.jdt.ui.prefs b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..470b007
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,139 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.push_down_negation=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_modifiers=false
+cleanup.remove_redundant_semicolons=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_array_creation=true
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_autoboxing=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup.use_unboxing=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=18
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#java;\#;\#org.eclipse.statet.jcommons;\#org.eclipse.statet.ecommons;\#org.eclipse.statet;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n \# \n \# This program and the accompanying materials are made available under the\n \# terms of the Eclipse Public License 2.0 which is available at\n \# https\://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n \# which is available at https\://www.apache.org/licenses/LICENSE-2.0.\n \# \n \# SPDX-License-Identifier\: EPL-2.0 OR Apache-2.0\n \# \n \# Contributors\:\n \#     ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+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_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=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.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+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=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_modifiers=false
+sp_cleanup.remove_redundant_semicolons=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+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=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/META-INF/MANIFEST.MF b/rhelp/org.eclipse.statet.rhelp.core-tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..095e32f
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rhelp.core.http.tests
+Bundle-Version: 4.1.0.qualifier
+Bundle-Vendor: Eclipse StatET
+Bundle-Name: StatET R-Help - Core - Tests  (Incubation)
+Fragment-Host: org.eclipse.statet.rhelp.core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: javax.servlet;version="3.1.0",
+ javax.servlet.http;version="3.1.0",
+ org.junit.jupiter.api;version="5.5.1",
+ org.junit.jupiter.api.function;version="5.5.1"
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/about.html b/rhelp/org.eclipse.statet.rhelp.core-tests/about.html
new file mode 100644
index 0000000..f094738
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/about.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 1, 2019</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless
+	otherwise indicated below, the Content is provided to you under the terms and conditions of the
+	Eclipse Public License Version 2.0 (&quot;EPL&quot;), or the Apache License, Version 2.0 (AL).
+	A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0"
+	>https://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, &quot;Program&quot; will
+	mean the Content. A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0"
+	>https://www.apache.org/licenses/LICENSE-2.0</a>.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being
+	redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions
+	may apply to your use of any object code in the Content. Check the Redistributor's license that
+	was provided with the Content. If no such license exists, contact the Redistributor. Unless
+	otherwise indicated below, the terms and conditions of the EPL or AL still apply to any source
+	code in the Content and such source code may be obtained at <a href="https://www.eclipse.org/"
+	>https://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/build.properties b/rhelp/org.eclipse.statet.rhelp.core-tests/build.properties
new file mode 100644
index 0000000..239dd55
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/build.properties
@@ -0,0 +1,8 @@
+source..= src/
+output..= target/classes/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+              .,\
+              about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/src/org/eclipse/statet/internal/rhelp/core/http/HttpHeaderTest.java b/rhelp/org.eclipse.statet.rhelp.core-tests/src/org/eclipse/statet/internal/rhelp/core/http/HttpHeaderTest.java
new file mode 100644
index 0000000..cf4b961
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/src/org/eclipse/statet/internal/rhelp/core/http/HttpHeaderTest.java
@@ -0,0 +1,259 @@
+/*=============================================================================#
+ # Copyright (c) 2019, 2020 Stephan Wahlbrink <sw@wahlbrink.eu> and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rhelp.core.http;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import org.eclipse.statet.jcommons.collections.BasicImMapEntry;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.IntArrayList;
+import org.eclipse.statet.jcommons.collections.IntList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils.MediaTypeEntry;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils.ParseException;
+
+
+@NonNullByDefault
+public class HttpHeaderTest {
+	
+	
+	public HttpHeaderTest() {
+	}
+	
+	
+	@Test
+	public void parseMediaTypes_empty() throws ParseException {
+		List<MediaTypeEntry> entries;
+		
+		entries= parseMediaTypes("");
+		assertEquals(0, entries.size());
+		
+		entries= parseMediaTypes("  	");
+		assertEquals(0, entries.size());
+	}
+	
+	@Test
+	public void parseMediaTypes_simple() throws ParseException {
+		List<MediaTypeEntry> entries;
+		
+		entries= parseMediaTypes("text/plain, text/html, text/x-dvi, */*");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "plain", 1f, ImCollections.emptyList()),
+				new MediaTypeEntry("text", "html", 1f, ImCollections.emptyList()),
+				new MediaTypeEntry("text", "x-dvi", 1f, ImCollections.emptyList()),
+				new MediaTypeEntry("*", "*", 1f, ImCollections.emptyList())
+		), entries );
+	}
+	
+	@Test
+	public void parseMediaTypes_withQualityFactor() throws ParseException {
+		List<MediaTypeEntry> entries;
+		
+		entries= parseMediaTypes("text/plain;q=0.1");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "plain", 0.1f, ImCollections.emptyList())
+		), entries );
+		
+		entries= parseMediaTypes("text/plain;   q=0.25");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "plain", 0.25f, ImCollections.emptyList())
+		), entries );
+		
+		entries= parseMediaTypes("text/plain; q=1  ");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "plain", 1f, ImCollections.emptyList())
+		), entries );
+	}
+	
+	@Test
+	public void parseMediaTypes_withQualityFactor_invalid() throws ParseException {
+		Assertions.assertThrows(ParseException.class,
+				() -> parseMediaTypes("text/plain;q") );
+		
+		Assertions.assertThrows(ParseException.class,
+				() -> parseMediaTypes("text/plain;q=") );
+		
+		Assertions.assertThrows(ParseException.class,
+				() -> parseMediaTypes("text/plain;q=text") );
+	}
+	
+	@Test
+	public void parseMediaTypes_withParameter() throws ParseException {
+		List<MediaTypeEntry> entries;
+		
+		entries= parseMediaTypes("text/html;level=1");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "html", 1f,  ImCollections.newList(
+						new BasicImMapEntry<>("level", "1") ))
+		), entries );
+		
+		entries= parseMediaTypes("application/x.org.eclipse.statet.rhelp-ds; ser=12");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.rhelp-ds", 1f,  ImCollections.newList(
+						new BasicImMapEntry<>("ser", "12") ))
+		), entries );
+		
+		entries= parseMediaTypes(" text/html;   level=1	; ext=  test  ");
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "html", 1f,  ImCollections.newList(
+						new BasicImMapEntry<>("level", "1"),
+						new BasicImMapEntry<>("ext", "test") ))
+		), entries );
+	}
+	
+	@Test
+	public void parseMediaTypes_precedence_bySpecific() throws ParseException {
+		List<MediaTypeEntry> entries;
+		
+		entries= parseMediaTypes("text/*, text/html, text/html;level=1, */*");
+		entries.sort(null);
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "html", 1f, ImCollections.newList(
+						new BasicImMapEntry<>("level", "1"))),
+				new MediaTypeEntry("text", "html", 1f, ImCollections.emptyList()),
+				new MediaTypeEntry("text", "*", 1f, ImCollections.emptyList()),
+				new MediaTypeEntry("*", "*", 1f, ImCollections.emptyList())
+		), entries );
+	}
+	
+	@Test
+	public void parseMediaTypes_precedence_byQualityFactor() throws ParseException {
+		List<MediaTypeEntry> entries;
+		
+		entries= parseMediaTypes("text/plain;q=0.1, text/html, text/x-dvi;q=0.5");
+		entries.sort(null);
+		assertMediaTypesEquals(ImCollections.newList(
+				new MediaTypeEntry("text", "html", 1f, ImCollections.emptyList()),
+				new MediaTypeEntry("text", "x-dvi", 0.5f, ImCollections.emptyList()),
+				new MediaTypeEntry("text", "plain", 0.1f, ImCollections.emptyList())
+		), entries );
+	}
+	
+	private List<MediaTypeEntry> parseMediaTypes(final String... headers) throws ParseException {
+		final List<MediaTypeEntry> entries= new ArrayList<>();
+		HttpHeaderUtils.parseMediaTypes(Collections.enumeration(Arrays.asList(headers)),
+				null, entries );
+		return entries;
+	}
+	
+	private void assertMediaTypesEquals(final List<MediaTypeEntry> expected, final List<MediaTypeEntry> entries) {
+		assertEquals(expected.size(), entries.size(), "count");
+		for (int i= 0; i < expected.size(); i++) {
+			final int i0= i;
+			assertEquals(expected.get(i), entries.get(i),
+					() -> String.format("media types differ at [%1$s] in basic properties", i0) );
+			assertEquals(expected.get(i).getQualityFactor(), entries.get(i).getQualityFactor(), 0f,
+					() -> String.format("media types differ at [%1$s] in qualityFactor ", i0) );
+		}
+	}
+	
+	
+	@Test
+	public void findFirstValid() {
+		List<MediaTypeEntry> entries;
+		int version;
+		
+		entries= ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.5f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "3") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.2f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "2") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.1f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "1") )) );
+		version= HttpHeaderUtils.findFirstValid(entries, "ver", (final int v) -> (v == 1));
+		assertEquals(1, version);
+		
+		entries= ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.5f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "3") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.2f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "2") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.1f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "1") )) );
+		version= HttpHeaderUtils.findFirstValid(entries, "ver", (final int v) -> (v == 3));
+		assertEquals(3, version);
+		
+		final IntList supportedVersions= new IntArrayList();
+		supportedVersions.add(4);
+		supportedVersions.add(2);
+		entries= ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.5f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "3") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.2f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "2") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.1f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "1") )) );
+		version= HttpHeaderUtils.findFirstValid(entries, "ver", (final int v) -> supportedVersions.contains(v));
+		assertEquals(2, version);
+	}
+	
+	@Test
+	public void findFirstValid_withMissingSpec() {
+		List<MediaTypeEntry> entries;
+		int version;
+		
+		entries= ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.5f, ImCollections.newList()),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.2f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "2") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.1f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "1") )) );
+		version= HttpHeaderUtils.findFirstValid(entries, "ver", (final int v) -> (v == 1));
+		assertEquals(1, version);
+	}
+	
+	@Test
+	public void findFirstValid_withInvalidSpec() {
+		List<MediaTypeEntry> entries;
+		int version;
+		
+		entries= ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.5f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.2f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "x") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.1f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "1") )) );
+		version= HttpHeaderUtils.findFirstValid(entries, "ver", (final int v) -> (v == 1));
+		assertEquals(1, version);
+	}
+	
+	@Test
+	public void findFirstValid_noValid() {
+		List<MediaTypeEntry> entries;
+		int version;
+		
+		entries= ImCollections.newList(
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.5f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "3") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.2f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "2") )),
+				new MediaTypeEntry("application", "x.org.eclipse.statet.test", 0.1f, ImCollections.newList(
+						new BasicImMapEntry<>("ver", "1") )) );
+		version= HttpHeaderUtils.findFirstValid(entries, "ver", (final int v) -> (v == 4));
+		assertEquals(-1, version);
+	}
+	
+	
+}
diff --git a/rhelp/org.eclipse.statet.rhelp.core-tests/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccessTest.java b/rhelp/org.eclipse.statet.rhelp.core-tests/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccessTest.java
new file mode 100644
index 0000000..4097894
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core-tests/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccessTest.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2019, 2020 Stephan Wahlbrink <sw@wahlbrink.eu> and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rhelp.core.server;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils.MediaTypeEntry;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils.ParseException;
+
+
+@NonNullByDefault
+public class ServerREnvHelpAccessTest {
+	
+	
+	public static String getVersionedDS_AccessHeader() {
+		return ServerREnvHelpAccess.DS_VERSIONED_ACCEPT_HEADER;
+	}
+	
+	public static String getModestDS_AccessHeader() {
+		return ServerREnvHelpAccess.DS_MODEST_ACCEPT_HEADER;
+	}
+	
+	
+	@Test
+	public void DS_VERSIONED_AcceptHeader_valid() throws ParseException {
+		final List<MediaTypeEntry> entries= HttpHeaderUtils.readMediaTypeEntries(Arrays.asList(getVersionedDS_AccessHeader()), null);
+		
+		for (final MediaTypeEntry entry : entries) {
+			assertEquals(ServerApi.APPLICATION_MEDIA_TYPE, entry.getType());
+			assertEquals(ServerApi.DS_MEDIA_SUBTYPE, entry.getSubtype());
+			assertNotNull(entry.getParameterValue(ServerApi.DS_SER_VERSION));
+		}
+	}
+	
+	@Test
+	public void DS_MODEST_AcceptHeader_valid() throws ParseException {
+		final List<MediaTypeEntry> entries= HttpHeaderUtils.readMediaTypeEntries(Arrays.asList(getModestDS_AccessHeader()), null);
+		
+		for (final MediaTypeEntry entry : entries) {
+			assertEquals(ServerApi.APPLICATION_MEDIA_TYPE, entry.getType());
+			assertEquals(ServerApi.DS_MEDIA_SUBTYPE, entry.getSubtype());
+		}
+	}
+	
+	
+}
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/FIO.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/DataStream.java
similarity index 93%
rename from rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/FIO.java
rename to rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/DataStream.java
index 5277b77..f57eecb 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/FIO.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/DataStream.java
@@ -32,28 +32,31 @@
 import org.eclipse.statet.jcommons.lang.Nullable;
 
 
+/**
+ * IO data stream for R help data.
+ */
 @NonNullByDefault
-public final class FIO implements AutoCloseable {
+public final class DataStream implements AutoCloseable {
 	
 	
-	private static final ThreadLocal<FIO> INSTANCES= new ThreadLocal<FIO>() {
+	private static final ThreadLocal<DataStream> INSTANCES= new ThreadLocal<DataStream>() {
 		
 		@Override
-		protected FIO initialValue() {
-			return new FIO();
+		protected DataStream initialValue() {
+			return new DataStream();
 		}
 		
 	};
 	
-	public static FIO get(final OutputStream out) {
-		final FIO io= INSTANCES.get();
+	public static DataStream get(final OutputStream out) {
+		final DataStream io= INSTANCES.get();
 		io.flags= OUT;
 		io.out.init(out);
 		return io;
 	}
 	
-	public static FIO get(final InputStream in) {
-		final FIO io= INSTANCES.get();
+	public static DataStream get(final InputStream in) {
+		final DataStream io= INSTANCES.get();
 		io.flags= IN;
 		io.in.init(in);
 		return io;
@@ -123,7 +126,7 @@
 		}
 		
 		public void enableCompression() {
-			FIO.this.flags |= COMPRESS;
+			DataStream.this.flags |= COMPRESS;
 			this.out= new DeflaterOutputStream(this.out, this.deflater, 4096);
 		}
 		
@@ -132,7 +135,7 @@
 			if (this.out != null) {
 				super.close();
 				this.out= null;
-				if ((FIO.this.flags & COMPRESS) != 0) {
+				if ((DataStream.this.flags & COMPRESS) != 0) {
 					this.deflater.reset();
 				}
 			}
@@ -157,7 +160,7 @@
 		}
 		
 		public void enableCompression() {
-			FIO.this.flags |= COMPRESS;
+			DataStream.this.flags |= COMPRESS;
 			this.in= new InflaterInputStream(this.in, this.inflater, 4096);
 		}
 		
@@ -166,7 +169,7 @@
 			if (this.in != null) {
 				super.close();
 				this.in= null;
-				if ((FIO.this.flags & COMPRESS) != 0) {
+				if ((DataStream.this.flags & COMPRESS) != 0) {
 					this.inflater.reset();
 				}
 			}
@@ -186,8 +189,10 @@
 	
 	private int flags;
 	
+	private int version;
 	
-	public FIO() {
+	
+	public DataStream() {
 		this.bb= ByteBuffer.allocateDirect(BB_LENGTH);
 		if (this.bb.hasArray()) {
 			this.mode= MODE_BBARRAY;
@@ -214,6 +219,7 @@
 			this.out.close();
 		}
 		this.flags= 0;
+		this.version= 0;
 	}
 	
 	public void enableCompression() {
@@ -228,6 +234,19 @@
 	}
 	
 	
+	public void writeVersion(final int version) throws IOException {
+		writeInt((this.version= version));
+	}
+	
+	public int readVersion() throws IOException {
+		return (this.version= readInt());
+	}
+	
+	public int getVersion() {
+		return this.version;
+	}
+	
+	
 	private void writeFullyBB(final int bn) throws IOException {
 		switch (this.mode) {
 		case MODE_BBARRAY:
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/SerUtil.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/SerUtil.java
index b26af2a..bfeb262 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/SerUtil.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/SerUtil.java
@@ -51,11 +51,13 @@
 public class SerUtil {
 	
 	
-	private static final int VERSION_11= 11;
-	private static final int VERSION_10= 10;
-	private static final int VERSION= VERSION_11;
+	public static final int VERSION_11= 11;
+	public static final int VERSION_10= 10;
+	public static final int CURRENT_VERSION= VERSION_11;
 	
-	public static final String READABLE_SERVER= "" + VERSION_11 + ',' + VERSION_10; //$NON-NLS-1$
+	public static final int[] READABLE_VERSIONS= {
+			VERSION_11,
+			VERSION_10 };
 	
 	private static final int COMPRESS= 1 << 4;
 	
@@ -150,10 +152,10 @@
 			final Path newFile= directory.resolve(RHELP_SER_FILE + ".new"); //$NON-NLS-1$
 			Files.deleteIfExists(newFile);
 			
-			try (final FIO fio= FIO.get(new BufferedOutputStream(
+			try (final DataStream out= DataStream.get(new BufferedOutputStream(
 					Files.newOutputStream(newFile, StandardOpenOption.CREATE_NEW) ))) {
-				save(help, fio, COMPRESS);
-				fio.flush();
+				save(help, out, COMPRESS);
+				out.flush();
 			}
 			
 			synchronized (controller.getFileLock()) {
@@ -184,7 +186,7 @@
 			
 			try (final OutputStream out= new BufferedOutputStream(
 					Files.newOutputStream(newFile, StandardOpenOption.CREATE_NEW) )) {
-				FIO.copy(in, out);
+				DataStream.copy(in, out);
 			}
 			
 			synchronized (controller.getFileLock()) {
@@ -213,13 +215,13 @@
 				return REnvHelpImpl.NOT_AVAILABLE_STAMP;
 			}
 			
-			try (final FIO fio= FIO.get(new BufferedInputStream(
+			try (final DataStream in= DataStream.get(new BufferedInputStream(
 					Files.newInputStream(serFile), 64 ))) {
-				final int version= fio.readInt();
-				if (version != VERSION && !canRead(version, rEnvConfig)) {
+				final int version= in.readVersion();
+				if (version != CURRENT_VERSION && !canRead(version, rEnvConfig)) {
 					return REnvHelpImpl.NOT_AVAILABLE_STAMP;
 				}
-				return fio.readLong();
+				return in.readLong();
 			}
 		}
 		catch (final Throwable e) {
@@ -241,9 +243,9 @@
 				return null;
 			}
 			
-			try (final FIO fio= FIO.get(new BufferedInputStream(
+			try (final DataStream in= DataStream.get(new BufferedInputStream(
 					Files.newInputStream(serFile) ))) {
-				return load(rEnvConfig, fio);
+				return load(rEnvConfig, in);
 			}
 		}
 		catch (final Throwable e) {
@@ -258,94 +260,94 @@
 		}
 	}
 	
-	public void save(final REnvHelpImpl help, final FIO fio, final int flags)
+	public void save(final REnvHelpImpl help, final DataStream out, final int flags)
 			throws IOException {
-		fio.writeInt(VERSION);
-		fio.writeLong(help.getStamp());
+		out.writeVersion(CURRENT_VERSION);
+		out.writeLong(help.getStamp());
 		
-		fio.writeInt(flags);
+		out.writeInt(flags);
 		if ((flags & COMPRESS) != 0) {
-			fio.enableCompression();
+			out.enableCompression();
 		}
 		
-		fio.writeString(help.getDocDir());
+		out.writeString(help.getDocDir());
 		{	final ImList<DocResource> resources= help.getManuals();
 			final int count= resources.size();
-			fio.writeInt(count);
+			out.writeInt(count);
 			for (int i= 0; i < count; i++) {
-				saveDocResource(resources.get(i), fio);
+				saveDocResource(resources.get(i), out);
 			}
 		}
 		{	final ImList<DocResource> resources= help.getMiscResources();
 			final int count= resources.size();
-			fio.writeInt(count);
+			out.writeInt(count);
 			for (int i= 0; i < count; i++) {
-				saveDocResource(resources.get(i), fio);
+				saveDocResource(resources.get(i), out);
 			}
 		}
 		
 		{	final List<RHelpKeywordGroup> keywordGroups= help.getKeywords();
 			final int count= keywordGroups.size();
-			fio.writeInt(count);
+			out.writeInt(count);
 			for (int i= 0; i < keywordGroups.size(); i++) {
-				saveKeywordGroup(keywordGroups.get(i), fio);
+				saveKeywordGroup(keywordGroups.get(i), out);
 			}
 		}
 		{	final List<RPkgHelp> packages= help.getPkgs();
 			final int count= packages.size();
-			fio.writeInt(count);
+			out.writeInt(count);
 			for (int i= 0; i < packages.size(); i++) {
-				savePackage(packages.get(i), fio);
+				savePackage(packages.get(i), out);
 			}
 		}
 	}
 	
-	public REnvHelpImpl load(final REnvHelpConfiguration rEnvConfig, final FIO fio)
+	public REnvHelpImpl load(final REnvHelpConfiguration rEnvConfig, final DataStream in)
 			throws IOException {
-		final int version= fio.readInt();
-		if (version != VERSION && !canRead(version, rEnvConfig)) {
+		final int version= in.readVersion();
+		if (version != CURRENT_VERSION && !canRead(version, rEnvConfig)) {
 			throw new UnsupportedVersionException(version);
 		}
 		
-		final long stamp= fio.readLong();
+		final long stamp= in.readLong();
 		
-		final int flags= fio.readInt();
+		final int flags= in.readInt();
 		if ((flags & COMPRESS) != 0) {
-			fio.enableCompression();
+			in.enableCompression();
 		}
 		
-		final String docDir= fio.readString();
+		final String docDir= in.readString();
 		final ImList<DocResource> manuals;
-		{	final int count= fio.readInt();
+		{	final int count= in.readInt();
 			final DocResource[] array= new org.eclipse.statet.rhelp.core.DocResource[count];
 			for (int i= 0; i < count; i++) {
-				array[i]= readDocResource(fio);
+				array[i]= readDocResource(in);
 			}
 			manuals= ImCollections.newList(array);
 		}
 		final ImList<DocResource> miscRes;
-		{	final int count= fio.readInt();
+		{	final int count= in.readInt();
 			final DocResource[] array= new @NonNull DocResource[count];
 			for (int i= 0; i < count; i++) {
-				array[i]= readDocResource(fio);
+				array[i]= readDocResource(in);
 			}
 			miscRes= ImCollections.newList(array);
 		}
 		
 		final ImList<RHelpKeywordGroup> keywordGroups;
-		{	final int count= fio.readInt();
+		{	final int count= in.readInt();
 			final RHelpKeywordGroup[] array= new @NonNull RHelpKeywordGroup[count];
 			for (int i= 0; i < count; i++) {
-				array[i]= loadKeywordGroup(fio);
+				array[i]= loadKeywordGroup(in);
 			}
 			keywordGroups= ImCollections.newList(array);
 		}
 		
 		final ImList<RPkgHelp> pkgHelps;
-		{	final int count= fio.readInt();
+		{	final int count= in.readInt();
 			final RPkgHelp[] array= new @NonNull RPkgHelp[count];
 			for (int i= 0; i < count; i++) {
-				array[i]= loadPackage(rEnvConfig, fio);
+				array[i]= loadPackage(rEnvConfig, in);
 			}
 			pkgHelps= ImCollections.newList(array);
 		}
@@ -357,117 +359,117 @@
 	
 	
 	private void saveDocResource(final DocResource res,
-			final FIO fio) throws IOException {
-		fio.writeString(res.getTitle());
-		fio.writeString(res.getPath());
-		fio.writeString(res.getPdfPath());
+			final DataStream out) throws IOException {
+		out.writeString(res.getTitle());
+		out.writeString(res.getPath());
+		out.writeString(res.getPdfPath());
 	}
 	
-	private DocResource readDocResource(final FIO fio) throws IOException {
+	private DocResource readDocResource(final DataStream in) throws IOException {
 		return new DocResource(
-				fio.readNonNullString(),
-				fio.readNonNullString(),
-				fio.readString() );
+				in.readNonNullString(),
+				in.readNonNullString(),
+				in.readString() );
 	}
 	
 	
 	private void saveKeywordGroup(final RHelpKeywordGroup group,
-			final FIO fio) throws IOException {
-		fio.writeString(group.getLabel());
-		fio.writeString(group.getDescription());
+			final DataStream out) throws IOException {
+		out.writeString(group.getLabel());
+		out.writeString(group.getDescription());
 		final List<RHelpKeyword> keywords= group.getNestedKeywords();
 		final int count= keywords.size();
-		fio.writeInt(count);
+		out.writeInt(count);
 		for (int i= 0; i < count; i++) {
-			saveKeyword(keywords.get(i), fio);
+			saveKeyword(keywords.get(i), out);
 		}
 	}
 	
-	private RHelpKeywordGroup loadKeywordGroup(final FIO fio) throws IOException {
-		final String label= fio.readString();
-		final String description= fio.readString();
-		final int count= fio.readInt();
+	private RHelpKeywordGroup loadKeywordGroup(final DataStream in) throws IOException {
+		final String label= in.readString();
+		final String description= in.readString();
+		final int count= in.readInt();
 		final RHelpKeyword[] keywords= new @NonNull RHelpKeyword[count];
 		for (int i= 0; i < count; i++) {
-			keywords[i]= loadKeyword(fio);
+			keywords[i]= loadKeyword(in);
 		}
 		return new RHelpKeywordGroupImpl(label, description, ImCollections.newList(keywords));
 	}
 	
-	private void saveKeyword(final RHelpKeyword keyword, final FIO fio)
+	private void saveKeyword(final RHelpKeyword keyword, final DataStream out)
 			throws IOException {
-		fio.writeString(keyword.getKeyword());
-		fio.writeString(keyword.getDescription());
+		out.writeString(keyword.getKeyword());
+		out.writeString(keyword.getDescription());
 		final List<RHelpKeyword> nestedKeywords= keyword.getNestedKeywords();
 		final int count= nestedKeywords.size();
-		fio.writeInt(count);
+		out.writeInt(count);
 		for (int i= 0; i < nestedKeywords.size(); i++) {
-			saveKeyword(nestedKeywords.get(i), fio);
+			saveKeyword(nestedKeywords.get(i), out);
 		}
 	}
 	
-	private RHelpKeyword loadKeyword(final FIO fio)
+	private RHelpKeyword loadKeyword(final DataStream in)
 			throws IOException {
-		final String keyword= fio.readString();
-		final String description= fio.readString();
-		final int n= fio.readInt();
+		final String keyword= in.readString();
+		final String description= in.readString();
+		final int n= in.readInt();
 		final RHelpKeyword[] nestedKeywords= new @NonNull RHelpKeyword[n];
 		for (int i= 0; i < n; i++) {
-			nestedKeywords[i]= loadKeyword(fio);
+			nestedKeywords[i]= loadKeyword(in);
 		}
 		return new RHelpKeywordImpl(keyword, description, ImCollections.newList(nestedKeywords));
 	}
 	
-	private void savePackage(final RPkgHelp pkgHelp, final FIO fio)
+	private void savePackage(final RPkgHelp pkgHelp, final DataStream out)
 			throws IOException {
-		savePkgDescription(pkgHelp.getPkgDescription(), fio);
+		savePkgDescription(pkgHelp.getPkgDescription(), out);
 		
 		final List<RHelpPage> pages= pkgHelp.getPages();
 		final int nPages= pages.size();
-		fio.writeInt(nPages);
+		out.writeInt(nPages);
 		for (int i= 0; i < nPages; i++) {
-			savePage(pages.get(i), fio);
+			savePage(pages.get(i), out);
 		}
 	}
 	
-	private RPkgHelp loadPackage(final REnvHelpConfiguration rEnvConfig, final FIO fio)
+	private RPkgHelp loadPackage(final REnvHelpConfiguration rEnvConfig, final DataStream in)
 			throws IOException {
-		final RPkgDescription pkgDescription= loadPkgDescription(rEnvConfig, fio);
+		final RPkgDescription pkgDescription= loadPkgDescription(rEnvConfig, in);
 		
-		final int nPages= fio.readInt();
+		final int nPages= in.readInt();
 		final RHelpPage[] pages= new @NonNull RHelpPage[nPages];
 		final RPkgHelpImpl pkg= new RPkgHelpImpl(pkgDescription, rEnvConfig.getREnv());
 		for (int i= 0; i < nPages; i++) {
-			pages[i]= loadPage(pkg, fio);
+			pages[i]= loadPage(pkg, in);
 		}
 		pkg.setPages(ImCollections.newList(pages));
 		return pkg;
 	}
 	
 	private void savePkgDescription(final RPkgDescription pkgDescription,
-			final FIO fio) throws IOException {
-		fio.writeString(pkgDescription.getName());
-		fio.writeString(pkgDescription.getVersion().toString());
-		fio.writeString(pkgDescription.getTitle());
-		fio.writeString(pkgDescription.getDescription());
-		fio.writeString(pkgDescription.getAuthor());
-		fio.writeString(pkgDescription.getMaintainer());
-		fio.writeString(pkgDescription.getUrl());
-		fio.writeString(pkgDescription.getBuilt());
-		fio.writeString(pkgDescription.getLibLocation().getDirectory());
+			final DataStream out) throws IOException {
+		out.writeString(pkgDescription.getName());
+		out.writeString(pkgDescription.getVersion().toString());
+		out.writeString(pkgDescription.getTitle());
+		out.writeString(pkgDescription.getDescription());
+		out.writeString(pkgDescription.getAuthor());
+		out.writeString(pkgDescription.getMaintainer());
+		out.writeString(pkgDescription.getUrl());
+		out.writeString(pkgDescription.getBuilt());
+		out.writeString(pkgDescription.getLibLocation().getDirectory());
 	}
 	
 	private RPkgDescription loadPkgDescription(final REnvHelpConfiguration rEnvConfig,
-			final FIO fio) throws IOException {
-		final String name= fio.readNonNullString().intern();
-		final String version= fio.readNonNullString();
-		final String title= fio.readNonNullString();
-		final String description= fio.readNonNullString();
-		final String author= fio.readString();
-		final String maintainer= fio.readString();
-		final String url= fio.readString();
-		final String built= fio.readNonNullString();
-		final RLibLocation libLocation= getLibLocationSafe(rEnvConfig, fio.readNonNullString());
+			final DataStream in) throws IOException {
+		final String name= in.readNonNullString().intern();
+		final String version= in.readNonNullString();
+		final String title= in.readNonNullString();
+		final String description= in.readNonNullString();
+		final String author= in.readString();
+		final String maintainer= in.readString();
+		final String url= in.readString();
+		final String built= in.readNonNullString();
+		final RLibLocation libLocation= getLibLocationSafe(rEnvConfig, in.readNonNullString());
 		
 		return new BasicRPkgDescription(name, RNumVersion.create(version),
 				title, description,
@@ -484,33 +486,33 @@
 		return libLocation;
 	}
 	
-	private void savePage(final RHelpPage page, final FIO fio)
+	private void savePage(final RHelpPage page, final DataStream out)
 			throws IOException {
-		fio.writeString(page.getName());
+		out.writeString(page.getName());
 		{	final ImList<String> topics= page.getTopics();
 			final int nTopics= topics.size();
-			fio.writeInt(nTopics);
+			out.writeInt(nTopics);
 			for (int i= 0; i < nTopics; i++) {
 				final String topic= topics.get(i);
-				fio.writeString((topic == page.getName()) ? null : topic);
+				out.writeString((topic == page.getName()) ? null : topic);
 			}
 		}
-		fio.writeString(page.getTitle());
+		out.writeString(page.getTitle());
 	}
 	
-	private RHelpPage loadPage(final RPkgHelp pkg, final FIO fio)
+	private RHelpPage loadPage(final RPkgHelp pkg, final DataStream in)
 			throws IOException {
-		final String name= fio.readNonNullString().intern();
+		final String name= in.readNonNullString().intern();
 		final ImList<String> topics;
-		{	final int nTopics= fio.readInt();
+		{	final int nTopics= in.readInt();
 			final String[] array= new @NonNull String[nTopics];
 			for (int i= 0; i < array.length; i++) {
-				final String topic= fio.readString();
+				final String topic= in.readString();
 				array[i]= (topic == null) ? name : topic.intern();
 			}
 			topics= ImCollections.newList(array);
 		}
-		final String title= fio.readNonNullString();
+		final String title= in.readNonNullString();
 		return new RHelpPageImpl(pkg, name, topics, title);
 	}
 	
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/BasicMediaType.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/BasicMediaType.java
new file mode 100644
index 0000000..ec4b4a0
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/BasicMediaType.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2019, 2020 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rhelp.core.http;
+// package org.eclipse.statet.jcommons.io;
+
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.collections.ImMapEntry;
+import org.eclipse.statet.jcommons.lang.Immutable;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+
+@NonNullByDefault
+public class BasicMediaType implements MediaType, Immutable {
+	
+	
+	private static String check(final String t) {
+		if (t.length() == 1 && t.charAt(0) == '*') {
+			return WILDCARD;
+		}
+		return t;
+	}
+	
+	protected static final int compare(final String t1, final String t2) {
+		if (t1 == WILDCARD) {
+			if (t2 == WILDCARD) {
+				return 0;
+			}
+			else {
+				return 1;
+			}
+		}
+		else if (t2 == WILDCARD) {
+			return -1;
+		}
+		else {
+			return t1.compareTo(t2);
+		}
+	}
+	
+	
+	private final String type;
+	private final String subtype;
+	private final ImList<? extends ImMapEntry<String, String>> parameters;
+	
+	
+	public BasicMediaType(final String type, final String subtype,
+			final ImList<? extends ImMapEntry<String, String>> parameters) {
+		this.type= check(type);
+		this.subtype= check(subtype);
+		this.parameters= parameters;
+	}
+	
+	@Override
+	public final String getType() {
+		return this.type;
+	}
+	
+	@Override
+	public final String getSubtype() {
+		return this.subtype;
+	}
+	
+	@Override
+	public ImList<? extends ImMapEntry<String, String>> getParameters() {
+		return this.parameters;
+	}
+	
+	
+//	public boolean includes(final MediaType type) {
+//		if (this.type == WILDCARD || this.type.equals(type.getType())) {
+//			if (this.subtype == WILDCARD || this.subtype.equals(type.getSubtype())) {
+//				return true;
+//			}
+//		}
+//		return false;
+//	}
+	
+	
+	@Override
+	public int hashCode() {
+		return this.type.hashCode() + this.subtype.hashCode() * 31;
+	}
+	
+	@Override
+	public boolean equals(final @Nullable Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj instanceof MediaType) {
+			final MediaType other= (MediaType)obj;
+			return (this.type.equals(other.getType())
+					&& this.subtype.equals(other.getSubtype())
+					&& getParameters().equals(other.getParameters()) );
+		}
+		return false;
+	}
+	
+}
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/HttpHeaderUtils.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/HttpHeaderUtils.java
new file mode 100644
index 0000000..5adfd40
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/HttpHeaderUtils.java
@@ -0,0 +1,472 @@
+/*=============================================================================#
+ # Copyright (c) 2019, 2020 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rhelp.core.http;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.function.BiPredicate;
+import java.util.function.IntPredicate;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.statet.jcommons.collections.BasicImMapEntry;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.collections.ImMapEntry;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+
+@NonNullByDefault
+public class HttpHeaderUtils {
+	
+	
+	public static final String LOCATION_NAME= "Location"; //$NON-NLS-1$
+	
+	public static final String ACCEPT_NAME= "Accept"; //$NON-NLS-1$
+	
+	public static final String QUALITY_FACTOR_PARAM_NAME= "q"; //$NON-NLS-1$
+	
+	
+	public static class MediaTypeEntry extends BasicMediaType implements Comparable<MediaTypeEntry> {
+		
+		
+		private final float qualityFactor;
+		
+		
+		public MediaTypeEntry(final String type, final String subtype,
+				final float qualityFactor, final ImList<? extends ImMapEntry<String, String>> extParams) {
+			super(type, subtype, extParams);
+			this.qualityFactor= qualityFactor;
+		}
+		
+		
+		public float getQualityFactor() {
+			return this.qualityFactor;
+		}
+		
+		
+		@Override
+		public int compareTo(final MediaTypeEntry o) {
+			{	final float diff= this.qualityFactor - o.qualityFactor;
+				if (diff != 0) {
+					return (diff > 0) ? -1 : 1;
+				}
+			}
+			{	final int diff= compare(getType(), o.getType());
+				if (diff != 0) {
+					return diff;
+				}
+			}
+			{	final int diff= compare(getSubtype(), o.getSubtype());
+				if (diff != 0) {
+					return diff;
+				}
+			}
+			return -(getParameters().size() - o.getParameters().size());
+		}
+		
+		
+	}
+	
+	public static class ParseException extends Exception {
+		
+		private static final long serialVersionUID= 1L;
+		
+		private final String errorDescription;
+		private final String input;
+		private final int errorOffset;
+		
+		public ParseException(final String errorDescription, final String input, final int errorOffset) {
+			super(String.format("Parse error: %1$s at %3$s in:\n%2$s", errorDescription, input, errorOffset));
+			this.errorDescription= errorDescription;
+			this.input= input;
+			this.errorOffset= errorOffset;
+		}
+		
+		
+		public String getErrorDescription() {
+			return this.errorDescription;
+		}
+		
+		public String getInput() {
+			return this.input;
+		}
+		
+		public int getErrorOffset() {
+			return this.errorOffset;
+		}
+		
+	}
+	
+	public static final class HeaderBuilder {
+		
+		
+		private final StringBuilder sb= new StringBuilder();
+		
+		
+		public HeaderBuilder() {
+		}
+		
+		
+		public void newEntry(final String value) {
+			if (this.sb.length() > 0) {
+				this.sb.append(',');
+			}
+			this.sb.append(value);
+		}
+		
+		public void newEntry(final String value, final float qValue) {
+			newEntry(value);
+			this.sb.append(';');
+			this.sb.append(QUALITY_FACTOR_PARAM_NAME);
+			this.sb.append('=');
+			this.sb.append(qValue);
+		}
+		
+		public void addParameter(final String name, final String value) {
+			this.sb.append(';');
+			this.sb.append(name);
+			this.sb.append('=');
+			this.sb.append(value);
+		}
+		
+		public String build() {
+			return this.sb.toString();
+		}
+		
+	}
+	
+	
+	private static class Tokenizer {
+		
+		private static boolean isLinearWhitespace(final char c) {
+			switch (c) {
+			case ' ':
+			case '\t':
+			case '\r':
+			case '\n':
+				return true;
+			default:
+				return false;
+			}
+		}
+		
+		private static boolean isSeparator(final char c) {
+			switch (c) {
+			case '(':
+			case ')':
+			case '<':
+			case '>':
+			case '@':
+			case ',':
+			case ';':
+			case ':':
+			case '\\':
+			case '"':
+			case '/':
+			case '[':
+			case ']':
+			case '?':
+			case '=':
+			case '{':
+			case '}':
+			case ' ':
+			case '\t':
+				return true;
+			default:
+				return false;
+			}
+		}
+		
+		private final String input;
+		
+		private int index;
+		
+		
+		public Tokenizer(final String input) {
+			this.input= input;
+		}
+		
+		
+		private int consumeWhitespace(int idx) {
+			while (idx < this.input.length() && isLinearWhitespace(this.input.charAt(idx))) {
+				idx++;
+			}
+			return idx;
+		}
+		
+		private int consumeToken(int idx) {
+			while (idx < this.input.length()) {
+				final char c= this.input.charAt(idx);
+				if (c > 0x20 && c < 0x7F && !isSeparator(c)) {
+					idx++;
+				}
+				else {
+					break;
+				}
+			}
+			return idx;
+		}
+		
+		public void readOperatorAssert(final char c) throws ParseException {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			if (idx < this.input.length() && this.input.charAt(idx) == c) {
+				this.index= idx + 1;
+				return;
+			}
+			throw new ParseException("operator '" + c + "' expected", this.input, idx);
+		}
+		
+		public String readTokenAssert() throws ParseException {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			final int start= idx;
+			idx= consumeToken(idx);
+			if (start < idx) {
+				this.index= idx;
+				return this.input.substring(start, idx);
+			}
+			throw new ParseException("token expected", this.input, idx);
+		}
+		
+		private String readParamValue(int idx) throws ParseException {
+			if (idx < this.input.length()) {
+				if (this.input.charAt(idx) == '"') {
+					idx++;
+					final int start= idx;
+					int end= -1;
+					while (idx < this.input.length()) {
+						final char c= this.input.charAt(idx);
+						switch (c) {
+						case '"':
+							end= idx;
+							idx++;
+							break;
+						case '\\':
+							idx++;
+							if (idx < this.input.length()) {
+								idx++;
+							}
+							continue;
+						default:
+							idx++;
+							continue;
+						}
+					}
+					this.index= idx;
+					if (end >= 0) {
+						return this.input.substring(start, end);
+					}
+					throw new ParseException("closing quote ('\"') expected", this.input, idx);
+				}
+				else {
+					final int start= idx;
+					idx= consumeToken(idx);
+					this.index= idx;
+					return this.input.substring(start, idx);
+				}
+			}
+			this.index= idx;
+			return "";
+		}
+		
+		public String readParamValue() throws ParseException {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			return readParamValue(idx);
+		}
+		
+		public void skipParamValue() throws ParseException {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			if (idx < this.input.length()) {
+				if (this.input.charAt(idx) == '"') {
+					idx++;
+					int end= -1;
+					while (idx < this.input.length()) {
+						final char c= this.input.charAt(idx);
+						switch (c) {
+						case '"':
+							end= idx;
+							idx++;
+							break;
+						case '\\':
+							idx++;
+							if (idx < this.input.length()) {
+								idx++;
+							}
+							continue;
+						default:
+							idx++;
+							continue;
+						}
+					}
+					this.index= idx;
+					if (end >= 0) {
+						return;
+					}
+					throw new ParseException("closing quote ('\"') expected", this.input, idx);
+				}
+				else {
+					idx= consumeToken(idx);
+					this.index= idx;
+					return;
+				}
+			}
+			this.index= idx;
+		}
+		
+		public float readQValue() throws ParseException {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			final int start= idx;
+			try {
+				idx= consumeToken(idx);
+				this.index= idx;
+				return Float.parseFloat(this.input.substring(start, idx));
+			}
+			catch (final NumberFormatException e) {
+				throw new ParseException("q value (number) expected", this.input, start);
+			}
+		}
+		
+		public boolean readNextEntry() {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			if (idx < this.input.length()) {
+				if (this.index == 0) {
+					return true;
+				}
+				if (this.input.charAt(idx) == ',') {
+					this.index= idx + 1;
+					return true;
+				}
+			}
+			this.index= idx;
+			return false;
+		}
+		
+		public boolean readNextParam() {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			if (idx < this.input.length() && this.input.charAt(idx) == ';') {
+				this.index= idx + 1;
+				return true;
+			}
+			this.index= idx;
+			return false;
+		}
+		
+		public void assertEnd() throws ParseException {
+			int idx= this.index;
+			idx= consumeWhitespace(idx);
+			this.index= idx;
+			if (idx == this.input.length()) {
+				return;
+			}
+			throw new ParseException("EOF expected", this.input, idx);
+		}
+		
+	}
+	
+	public static List<MediaTypeEntry> readAcceptHeaderEntries(final HttpServletRequest req,
+			final @Nullable BiPredicate<String, String> filter)
+			throws ServletException {
+		try {
+			final List<MediaTypeEntry> entries= new ArrayList<>();
+			final Enumeration<String> headers= req.getHeaders(ACCEPT_NAME);
+			if (headers != null) {
+				parseMediaTypes(headers, filter, entries);
+			}
+			entries.sort(null);
+			return entries;
+		}
+		catch (final ParseException e) {
+			throw new ServletException("Failed to read Accept header of request.", e);
+		}
+	}
+	
+	public static List<MediaTypeEntry> readMediaTypeEntries(final Collection<String> headers,
+			final @Nullable BiPredicate<String, String> filter)
+			throws ParseException {
+		final List<MediaTypeEntry> entries= new ArrayList<>();
+		if (!headers.isEmpty()) {
+			parseMediaTypes(Collections.enumeration(headers), filter, entries);
+		}
+		entries.sort(null);
+		return entries;
+	}
+	
+	protected final static void parseMediaTypes(final Enumeration<String> headers,
+			final @Nullable BiPredicate<String, String> filter, final List<MediaTypeEntry> entries) throws ParseException {
+		final List<ImMapEntry<String, String>> extParams= new ArrayList<>();
+		while (headers.hasMoreElements()) {
+			final Tokenizer tokenizer= new Tokenizer(headers.nextElement());
+			while (tokenizer.readNextEntry()) {
+				extParams.clear();
+				
+				final String type= tokenizer.readTokenAssert();
+				tokenizer.readOperatorAssert('/');
+				final String subtype= tokenizer.readTokenAssert();
+				
+				final boolean include= (filter == null || filter.test(type, subtype));
+				float qValue= 1;
+				for (int nParam= 0; tokenizer.readNextParam(); nParam++) {
+					final String paramName= tokenizer.readTokenAssert();
+					tokenizer.readOperatorAssert('=');
+					if (!include) {
+						tokenizer.skipParamValue();
+						continue;
+					}
+					if (nParam == 0 && paramName.equals(QUALITY_FACTOR_PARAM_NAME)) {
+						qValue= tokenizer.readQValue();
+					}
+					else {
+						final String paramValue= tokenizer.readParamValue();
+						extParams.add(new BasicImMapEntry<>(paramName, paramValue));
+					}
+				}
+				entries.add(new MediaTypeEntry(type, subtype, qValue,
+						ImCollections.toList(extParams) ));
+			}
+			tokenizer.assertEnd();
+		}
+	}
+	
+	
+	public static int findFirstValid(final List<MediaTypeEntry> entries,
+			final String parameterName, final IntPredicate paramPredicate) {
+		for (final MediaTypeEntry entry : entries) {
+			final String vString= entry.getParameterValue(parameterName);
+			if (vString != null) {
+				try {
+					final int v= Integer.parseInt(vString);
+					if (paramPredicate.test(v)) {
+						return v;
+					}
+				}
+				catch (final NumberFormatException e) {}
+			}
+		}
+		return -1;
+	}
+	
+}
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/MediaType.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/MediaType.java
new file mode 100644
index 0000000..fefb770
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/http/MediaType.java
@@ -0,0 +1,48 @@
+/*=============================================================================#
+ # Copyright (c) 2019, 2020 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rhelp.core.http;
+//package org.eclipse.statet.jcommons.io;
+
+import java.util.Map;
+
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+
+@NonNullByDefault
+public interface MediaType {
+	
+	String WILDCARD= "*";
+	
+	
+	String getType();
+	
+	String getSubtype();
+	
+	
+	ImList<? extends Map.Entry<String, String>> getParameters();
+	
+	default @Nullable String getParameterValue(final String name) {
+		final ImList<? extends Map.Entry<String, String>> parameters= getParameters();
+		for (final Map.Entry<String, String> parameter : parameters) {
+			if (parameter.getKey().equals(name)) {
+				return parameter.getValue();
+			}
+		}
+		return null;
+	}
+	
+}
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/JettyREnvHelpAccess.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/JettyREnvHelpAccess.java
index b220053..da6d7a8 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/JettyREnvHelpAccess.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/JettyREnvHelpAccess.java
@@ -40,8 +40,6 @@
 import org.eclipse.statet.jcommons.status.ProgressMonitor;
 import org.eclipse.statet.jcommons.status.StatusException;
 
-import org.eclipse.statet.internal.rhelp.core.SerUtil;
-
 
 @NonNullByDefault
 public class JettyREnvHelpAccess extends ServerREnvHelpAccess {
@@ -77,7 +75,7 @@
 			throw new ResponseException(message);
 		}
 		final String contentType= response.getHeaders().get(HttpHeader.CONTENT_TYPE);
-		if (contentType == null || !contentType.startsWith(ServerApi.DS_MIME_TYPE)) {
+		if (contentType == null || !contentType.startsWith(ServerApi.DS_MEDIA_TYPE_STRING)) {
 			throw new ResponseException(String.format("Unexpected content type: '%1$s'.",
 					contentType ));
 		}
@@ -90,7 +88,7 @@
 		if (eTag != null) {
 			request.header(HttpHeader.IF_NONE_MATCH, eTag);
 		}
-		request.accept(ServerApi.DS_MIME_TYPE + ';' + ServerApi.DS_SER_VERSION + '=' + SerUtil.READABLE_SERVER);
+		request.accept(DS_VERSIONED_ACCEPT_HEADER);
 		
 		return doGetDataStream(request, (eTag != null));
 	}
@@ -103,14 +101,15 @@
 			request.param(params[i++], params[i++]);
 		}
 		request.method(HttpMethod.POST);
-		request.content(new BytesContentProvider(ServerApi.DS_MIME_TYPE, requestData));
+		request.content(new BytesContentProvider(ServerApi.DS_MEDIA_TYPE_STRING, requestData));
+		
+		request.accept(DS_MODEST_ACCEPT_HEADER);
 		
 		return doGetDataStream(request, false);
 	}
 	
 	private @Nullable InputStream doGetDataStream(final Request request, final boolean notModified)
 			throws StatusException, ResponseException {
-		request.accept(ServerApi.DS_MIME_TYPE);
 		
 		final InputStreamResponseListener listener= new InputStreamResponseListener();
 		request.send(listener);
@@ -154,7 +153,7 @@
 			request.param(params[i++], params[i++]);
 		}
 		
-		request.accept(ServerApi.DS_MIME_TYPE);
+		request.accept(DS_MODEST_ACCEPT_HEADER);
 		if (timeout != -1) {
 			request.timeout(timeout, TimeUnit.SECONDS);
 		}
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerApi.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerApi.java
index f4678a1..5425912 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerApi.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerApi.java
@@ -29,7 +29,9 @@
 	
 	public static final String API_VERSION_1= "api/v1"; //$NON-NLS-1$
 	
-	public static final String DS_MIME_TYPE= "application/x.org.eclipse.statet.rhelp-ds"; //$NON-NLS-1$
+	public static final String APPLICATION_MEDIA_TYPE= "application"; //$NON-NLS-1$
+	public static final String DS_MEDIA_SUBTYPE= "x.org.eclipse.statet.rhelp-ds"; //$NON-NLS-1$
+	public static final String DS_MEDIA_TYPE_STRING= APPLICATION_MEDIA_TYPE + '/' + DS_MEDIA_SUBTYPE;
 	
 	public static final String DS_SER_VERSION= "ser"; //$NON-NLS-1$
 	
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccess.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccess.java
index 44cbc55..7aeff0b 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccess.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/internal/rhelp/core/server/ServerREnvHelpAccess.java
@@ -37,12 +37,13 @@
 import org.eclipse.statet.jcommons.status.StatusException;
 import org.eclipse.statet.jcommons.status.Statuses;
 
-import org.eclipse.statet.internal.rhelp.core.FIO;
+import org.eclipse.statet.internal.rhelp.core.DataStream;
 import org.eclipse.statet.internal.rhelp.core.REnvHelpIndex;
 import org.eclipse.statet.internal.rhelp.core.RHelpSearchMatchImpl;
 import org.eclipse.statet.internal.rhelp.core.RHelpWebapp;
 import org.eclipse.statet.internal.rhelp.core.SerUtil;
 import org.eclipse.statet.internal.rhelp.core.SerUtil.Controller;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils;
 import org.eclipse.statet.rhelp.core.REnvHelpConfiguration;
 import org.eclipse.statet.rhelp.core.RHelpCore;
 import org.eclipse.statet.rhelp.core.RHelpPage;
@@ -58,6 +59,18 @@
 	
 	protected static final String[] NO_PARAMS= new String[0];
 	
+	protected static final String DS_MODEST_ACCEPT_HEADER= ServerApi.DS_MEDIA_TYPE_STRING;
+	protected static final String DS_VERSIONED_ACCEPT_HEADER;
+	static {
+		final HttpHeaderUtils.HeaderBuilder builder= new HttpHeaderUtils.HeaderBuilder();
+		final int[] acceptedVersions= SerUtil.READABLE_VERSIONS;
+		for (int i= 0; i < acceptedVersions.length; i++) {
+			builder.newEntry(ServerApi.DS_MEDIA_TYPE_STRING, (10 - i)/10.0f);
+			builder.addParameter(ServerApi.DS_SER_VERSION, Integer.toString(acceptedVersions[i]));
+		}
+		DS_VERSIONED_ACCEPT_HEADER= builder.build();
+	}
+	
 	
 	private final URI url;
 	
@@ -197,15 +210,15 @@
 	@Override
 	public List<RHelpPage> getPagesForTopic(final String topic, final Map<String, RPkgHelp> packageMap,
 			final int timeout, final @Nullable ProgressMonitor m) throws StatusException {
-		try (final FIO fio= FIO.get(new ByteArrayInputStream(getDataStreamBytes(
+		try (final DataStream in= DataStream.get(new ByteArrayInputStream(getDataStreamBytes(
 				createUrl(createPath(ServerApi.PAGES)), new String[] {
 						ServerApi.TOPIC_PARAM, topic,
 				}, timeout, m)))) {
-			final int n= fio.readInt();
+			final int n= in.readInt();
 			final List<RHelpPage> pages= new ArrayList<>(n);
 			for (int i= 0; i < n; i++) {
-				final String pkgName= nonNullAssert(fio.readString());
-				final String pageName= nonNullAssert(fio.readString());
+				final String pkgName= nonNullAssert(in.readString());
+				final String pageName= nonNullAssert(in.readString());
 				final RPkgHelp pkgHelp= packageMap.get(pkgName);
 				if (pkgHelp != null) {
 					final RHelpPage page= pkgHelp.getPage(pageName);
@@ -226,13 +239,13 @@
 	public @Nullable String getHtmlPage(final RPkgHelp pkgHelp, final String pageName,
 			final @Nullable String queryString,
 			final int timeout, final @Nullable ProgressMonitor m) throws StatusException {
-		try (final FIO fio= FIO.get(new ByteArrayInputStream(getDataStreamBytes(
+		try (final DataStream in= DataStream.get(new ByteArrayInputStream(getDataStreamBytes(
 				createUrl(createPath(ServerApi.PKGS, pkgHelp.getName(), ServerApi.PAGES, pageName)),
 						(queryString != null) ? new String[] {
 								ServerApi.QUERY_STRING_PARAM, queryString,
 						} : NO_PARAMS,
 						timeout, m )))) {
-			return fio.readString();
+			return in.readString();
 		}
 		catch (final NotFoundException e) {
 			return null;
@@ -250,37 +263,37 @@
 			final Map<String, RPkgHelp> packageMap,
 			final RHelpSearchRequestor requestor) throws StatusException {
 		final ByteArrayOutputStream requestData= new ByteArrayOutputStream();
-		try (final FIO fio= FIO.get(requestData)) {
-			fio.writeInt(searchQuery.getSearchType());
-			fio.writeString(searchQuery.getSearchString());
-			fio.writeStringList(searchQuery.getEnabledFields());
-			fio.writeStringList(searchQuery.getKeywords());
-			fio.writeStringList(searchQuery.getPackages());
+		try (final DataStream out= DataStream.get(requestData)) {
+			out.writeInt(searchQuery.getSearchType());
+			out.writeString(searchQuery.getSearchString());
+			out.writeStringList(searchQuery.getEnabledFields());
+			out.writeStringList(searchQuery.getKeywords());
+			out.writeStringList(searchQuery.getPackages());
 		}
 		catch (final Exception e) {
 			throw onFailed(e);
 		}
-		try (final FIO fio= FIO.get(getDataStream(
+		try (final DataStream in= DataStream.get(getDataStream(
 				createUrl(createPath(ServerApi.SEARCH)), new String[] {
 						ServerApi.MAX_FRAGMENTS_PARAM, Integer.toString(requestor.getMaxFragments()),
 				}, requestData.toByteArray() ))) {
 			while (true) {
-				final byte matchType= fio.readByte();
+				final byte matchType= in.readByte();
 				switch (matchType) {
 				case ServerApi.END_MATCH:
 					return;
 				case ServerApi.PAGE_MATCH: {
-					final String pkgName= fio.readNonNullString();
-					final String pageName= fio.readNonNullString();
-					final float score= fio.readFloat();
-					final int matchCount= fio.readInt();
+					final String pkgName= in.readNonNullString();
+					final String pageName= in.readNonNullString();
+					final float score= in.readFloat();
+					final int matchCount= in.readInt();
 					final MatchFragment[] fragments;
 					if (matchCount >= 0) {
-						final int nFragments= fio.readInt();
+						final int nFragments= in.readInt();
 						fragments= new @NonNull MatchFragment[nFragments];
 						for (int i= 0; i < nFragments; i++) {
-							final String field= fio.readNonNullString();
-							final String text= fio.readNonNullString();
+							final String field= in.readNonNullString();
+							final String text= in.readNonNullString();
 							fragments[i]= new RHelpSearchMatchImpl.Fragment(field, text);
 						}
 					}
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/CustomMimeTypes.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/CustomMediaTypeProvider.java
similarity index 74%
rename from rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/CustomMimeTypes.java
rename to rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/CustomMediaTypeProvider.java
index 11b9de1..50a5d29 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/CustomMimeTypes.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/CustomMediaTypeProvider.java
@@ -22,27 +22,27 @@
 
 
 @NonNullByDefault
-public class CustomMimeTypes implements MimeTypes {
+public class CustomMediaTypeProvider implements MediaTypeProvider {
 	
 	
 	private final Map<String, String> nameTypes= new HashMap<>();
 	private final Map<String, String> extTypes= new HashMap<>();
 	
 	
-	public CustomMimeTypes() {
+	public CustomMediaTypeProvider() {
 	}
 	
 	
-	public void addName(final String fileName, final String type) {
-		this.nameTypes.put(fileName, type);
+	public void addName(final String fileName, final String mediaTypeString) {
+		this.nameTypes.put(fileName, mediaTypeString);
 	}
 	
-	public void addExt(final String fileExt, final String type) {
-		this.extTypes.put(fileExt, type);
+	public void addExt(final String fileExt, final String mediaTypeString) {
+		this.extTypes.put(fileExt, mediaTypeString);
 	}
 	
 	@Override
-	public @Nullable String getMimeType(final String fileName) {
+	public @Nullable String getMediaTypeString(final String fileName) {
 		String type= this.nameTypes.get(fileName);
 		if (type == null) {
 			final int idx= fileName.indexOf('.');
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/MimeTypes.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/MediaTypeProvider.java
similarity index 89%
rename from rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/MimeTypes.java
rename to rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/MediaTypeProvider.java
index 47c0da9..81f5a3e 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/MimeTypes.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/MediaTypeProvider.java
@@ -19,9 +19,9 @@
 
 
 @NonNullByDefault
-public interface MimeTypes {
+public interface MediaTypeProvider {
 	
 	
-	@Nullable String getMimeType(final String fileName);
+	@Nullable String getMediaTypeString(final String fileName);
 	
 }
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpApi1Servlet.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpApi1Servlet.java
index 4fbfe90..c595c5c 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpApi1Servlet.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpApi1Servlet.java
@@ -35,9 +35,11 @@
 import org.eclipse.statet.jcommons.lang.Nullable;
 import org.eclipse.statet.jcommons.status.StatusException;
 
-import org.eclipse.statet.internal.rhelp.core.FIO;
+import org.eclipse.statet.internal.rhelp.core.DataStream;
 import org.eclipse.statet.internal.rhelp.core.REnvHelpImpl;
 import org.eclipse.statet.internal.rhelp.core.SerUtil;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils.MediaTypeEntry;
 import org.eclipse.statet.internal.rhelp.core.server.ServerApi;
 import org.eclipse.statet.internal.rhelp.core.server.ServerApi.RequestInfo;
 import org.eclipse.statet.rhelp.core.REnvHelp;
@@ -79,11 +81,11 @@
 	}
 	
 	
-	private static final MimeTypes API_MIME_TYPES;
+	private static final MediaTypeProvider API_MEDIA_TYPE_PROVIDER;
 	static {
-		final CustomMimeTypes apiMimeTypes= new CustomMimeTypes();
-		apiMimeTypes.addExt("ser", ServerApi.DS_MIME_TYPE); //$NON-NLS-1$
-		API_MIME_TYPES= apiMimeTypes;
+		final CustomMediaTypeProvider apiMediaTypes= new CustomMediaTypeProvider();
+		apiMediaTypes.addExt("ser", ServerApi.DS_MEDIA_TYPE_STRING); //$NON-NLS-1$
+		API_MEDIA_TYPE_PROVIDER= apiMediaTypes;
 	}
 	
 	
@@ -117,8 +119,8 @@
 			final @Nullable ResourceHandler resourceHandler) {
 		this.rHelpManager= rHelpManager;
 		this.resourceHandler= (resourceHandler != null) ? resourceHandler :
-			new SimpleResourceHandler(new ServletMimeTypes(getServletContext()));
-		this.resourceHandler.setSpecialMimeTypes(API_MIME_TYPES);
+			new SimpleResourceHandler(new ServletMediaTypeProvider(getServletContext()));
+		this.resourceHandler.setSpecialMediaTypes(API_MEDIA_TYPE_PROVIDER);
 		this.resourceHandler.setCacheControl("max-age=100, must-revalidate"); //$NON-NLS-1$
 	}
 	
@@ -258,13 +260,22 @@
 			final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
 		final REnvHelpImpl help= getEnvHelp(req);
 		
-		resp.setContentType(ServerApi.DS_MIME_TYPE);
+		resp.setContentType(ServerApi.DS_MEDIA_TYPE_STRING);
 		try (final OutputStream out= resp.getOutputStream()) {
-			out.write(FIO.encodeLong(help.getStamp()));
+			out.write(DataStream.encodeLong(help.getStamp()));
 		}
 	}
 	
 	
+	protected int checkAcceptDS(final HttpServletRequest req) throws ServletException {
+		final List<MediaTypeEntry> entries= HttpHeaderUtils.readAcceptHeaderEntries(req,
+				(final String type, final String subtype) ->
+						(type.equals(ServerApi.APPLICATION_MEDIA_TYPE)
+								&& subtype.equals(ServerApi.DS_MEDIA_SUBTYPE) ));
+		return HttpHeaderUtils.findFirstValid(entries, ServerApi.DS_SER_VERSION,
+				(final int v) -> (v == SerUtil.CURRENT_VERSION) );
+	}
+	
 	private void processBasicData(
 			final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
 		final REnvHelpConfiguration config= (REnvHelpConfiguration) req.getAttribute(ATTR_RENV_CONFIG);
@@ -284,6 +295,11 @@
 			}
 		}
 		
+		final int serVersion= checkAcceptDS(req);
+		if (serVersion < 0) {
+			resp.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE);
+			return;
+		}
 		final Path file= SerUtil.getBasicDataFilePath(config);
 		if (file != null && Files.isRegularFile(file)) {
 			this.resourceHandler.doGet(file, req, resp);
@@ -334,13 +350,13 @@
 			pages= pkgHelp.getPages();
 		}
 		
-		resp.setContentType(ServerApi.DS_MIME_TYPE);
-		try (final FIO fio= FIO.get(resp.getOutputStream())) {
+		resp.setContentType(ServerApi.DS_MEDIA_TYPE_STRING);
+		try (final DataStream out= DataStream.get(resp.getOutputStream())) {
 			final int n= pages.size();
-			fio.writeInt(n);
+			out.writeInt(n);
 			for (int i= 0; i < n; i++) {
 				final RHelpPage page= pages.get(i);
-				fio.writeString(page.getName());
+				out.writeString(page.getName());
 			}
 		}
 	}
@@ -358,9 +374,9 @@
 			return;
 		}
 		
-		resp.setContentType(ServerApi.DS_MIME_TYPE);
-		try (final FIO fio= FIO.get(resp.getOutputStream())) {
-			fio.writeString(html);
+		resp.setContentType(ServerApi.DS_MEDIA_TYPE_STRING);
+		try (final DataStream out= DataStream.get(resp.getOutputStream())) {
+			out.writeString(html);
 		}
 	}
 	
@@ -373,14 +389,14 @@
 		if (topic != null) {
 			final List<RHelpPage> pages= help.getPagesForTopic(topic, null);
 			
-			resp.setContentType(ServerApi.DS_MIME_TYPE);
-			try (final FIO fio= FIO.get(resp.getOutputStream())) {
+			resp.setContentType(ServerApi.DS_MEDIA_TYPE_STRING);
+			try (final DataStream out= DataStream.get(resp.getOutputStream())) {
 				final int n= pages.size();
-				fio.writeInt(n);
+				out.writeInt(n);
 				for (int i= 0; i < n; i++) {
 					final RHelpPage page= pages.get(i);
-					fio.writeString(page.getPackage().getName());
-					fio.writeString(page.getName());
+					out.writeString(page.getPackage().getName());
+					out.writeString(page.getName());
 				}
 			}
 		}
@@ -388,13 +404,13 @@
 	
 	private @Nullable RHelpSearchQuery readRHelpSearchQuery(
 			final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-		if (req.getContentType() != null && req.getContentType().equals(ServerApi.DS_MIME_TYPE)) {
-			try (final FIO fio= FIO.get(req.getInputStream())) {
-				final int searchType= fio.readInt();
-				final String searchString= fio.readNonNullString();
-				final ImList<String >fields= ImCollections.newList(fio.readNonNullStringArray());
-				final ImList<String >keywords= ImCollections.newList(fio.readNonNullStringArray());
-				final ImList<String >packages= ImCollections.newList(fio.readNonNullStringArray());
+		if (req.getContentType() != null && req.getContentType().equals(ServerApi.DS_MEDIA_TYPE_STRING)) {
+			try (final DataStream in= DataStream.get(req.getInputStream())) {
+				final int searchType= in.readInt();
+				final String searchString= in.readNonNullString();
+				final ImList<String >fields= ImCollections.newList(in.readNonNullStringArray());
+				final ImList<String >keywords= ImCollections.newList(in.readNonNullStringArray());
+				final ImList<String >packages= ImCollections.newList(in.readNonNullStringArray());
 				return new RHelpSearchQuery(searchType, searchString, fields,
 						keywords, packages,
 						getEnv(req) );
@@ -444,9 +460,9 @@
 			return;
 		}
 		
-		resp.setContentType(ServerApi.DS_MIME_TYPE);
+		resp.setContentType(ServerApi.DS_MEDIA_TYPE_STRING);
 		resp.flushBuffer();
-		try (final FIO fio= FIO.get(resp.getOutputStream())) {
+		try (final DataStream out= DataStream.get(resp.getOutputStream())) {
 			help.search(searchQuery, new RHelpSearchRequestor() {
 				
 				@Override
@@ -457,21 +473,21 @@
 				@Override
 				public void matchFound(final RHelpSearchMatch match) {
 					try {
-						fio.writeByte(ServerApi.PAGE_MATCH);
+						out.writeByte(ServerApi.PAGE_MATCH);
 						{	final RHelpPage page= match.getPage();
-							fio.writeString(page.getPackage().getName());
-							fio.writeString(page.getName());
+							out.writeString(page.getPackage().getName());
+							out.writeString(page.getName());
 						}
-						fio.writeFloat(match.getScore());
-						fio.writeInt(match.getMatchCount());
+						out.writeFloat(match.getScore());
+						out.writeInt(match.getMatchCount());
 						if (match.getMatchCount() >= 0) {
 							final MatchFragment[] fragments= nonNullAssert(match.getBestFragments());
 							final int nFragments= fragments.length;
-							fio.writeInt(nFragments);
+							out.writeInt(nFragments);
 							for (int i= 0; i < nFragments; i++) {
 								final MatchFragment fragment= fragments[i];
-								fio.writeString(fragment.getField());
-								fio.writeString(fragment.getText());
+								out.writeString(fragment.getField());
+								out.writeString(fragment.getText());
 							}
 						}
 					}
@@ -481,7 +497,7 @@
 				}
 				
 			});
-			fio.writeInt(ServerApi.END_MATCH);
+			out.writeInt(ServerApi.END_MATCH);
 		}
 		catch (final WrappedIOException e) {
 			throw e.getCause();
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpHttpServlet.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpHttpServlet.java
index 751f427..c8e5f74 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpHttpServlet.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/RHelpHttpServlet.java
@@ -38,8 +38,6 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.http.HttpHeader;
-
 import org.eclipse.statet.jcommons.collections.ImCollections;
 import org.eclipse.statet.jcommons.collections.ImList;
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
@@ -51,6 +49,7 @@
 import org.eclipse.statet.internal.rhelp.core.REnvHelpIndex;
 import org.eclipse.statet.internal.rhelp.core.RHelpWebapp;
 import org.eclipse.statet.internal.rhelp.core.RHelpWebapp.RequestInfo;
+import org.eclipse.statet.internal.rhelp.core.http.HttpHeaderUtils;
 import org.eclipse.statet.internal.rhelp.core.index.RHelpHtmlUtils;
 import org.eclipse.statet.internal.rhelp.core.server.ServerClientSupport;
 import org.eclipse.statet.rhelp.core.DocResource;
@@ -84,17 +83,17 @@
 	private static final String ATTR_RENV_CONFIG= "rhelp.renv.config"; //$NON-NLS-1$
 	
 	
-	private static final MimeTypes DOC_MIME_TYPES;
+	private static final MediaTypeProvider DOC_MEDIA_TYPES;
 	static {
-		final CustomMimeTypes docMimeTypes= new CustomMimeTypes();
-		docMimeTypes.addName("README", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
-		docMimeTypes.addName("COPYING", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
-		docMimeTypes.addName("LICENSE", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
-		docMimeTypes.addName("AUTHORS", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
-		docMimeTypes.addName("THANKS", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
-		docMimeTypes.addName("DESCRIPTION", "text/plain"); //$NON-NLS-1$ //$NON-NLS-2$
-		docMimeTypes.addExt("Rnw", "text/plain"); //$NON-NLS-1$ //$NON-NLS-2$
-		DOC_MIME_TYPES= docMimeTypes;
+		final CustomMediaTypeProvider docMediaTypes= new CustomMediaTypeProvider();
+		docMediaTypes.addName("README", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
+		docMediaTypes.addName("COPYING", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
+		docMediaTypes.addName("LICENSE", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
+		docMediaTypes.addName("AUTHORS", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
+		docMediaTypes.addName("THANKS", "text/plain;charset=iso-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
+		docMediaTypes.addName("DESCRIPTION", "text/plain"); //$NON-NLS-1$ //$NON-NLS-2$
+		docMediaTypes.addExt("Rnw", "text/plain"); //$NON-NLS-1$ //$NON-NLS-2$
+		DOC_MEDIA_TYPES= docMediaTypes;
 	}
 	
 	@SuppressWarnings("null")
@@ -187,8 +186,8 @@
 		this.rHelpManager= rHelpManager;
 		
 		this.fileResourceHandler= (fileResourceHandler != null) ? fileResourceHandler :
-				new SimpleResourceHandler(new ServletMimeTypes(getServletContext()));
-		this.fileResourceHandler.setSpecialMimeTypes(DOC_MIME_TYPES);
+				new SimpleResourceHandler(new ServletMediaTypeProvider(getServletContext()));
+		this.fileResourceHandler.setSpecialMediaTypes(DOC_MEDIA_TYPES);
 		this.fileResourceHandler.setCacheControl("max-age=600, must-revalidate"); //$NON-NLS-1$
 		
 		this.serverForwardHandler= serverForwardHandler;
@@ -293,7 +292,7 @@
 		
 		resp.resetBuffer();
 		resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
-		resp.setHeader(HttpHeader.LOCATION.asString(), path);
+		resp.setHeader(HttpHeaderUtils.LOCATION_NAME, path);
 	}
 	
 	
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ResourceHandler.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ResourceHandler.java
index 932f623..5ff406b 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ResourceHandler.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ResourceHandler.java
@@ -28,7 +28,7 @@
 public interface ResourceHandler {
 	
 	
-	void setSpecialMimeTypes(final MimeTypes types);
+	void setSpecialMediaTypes(final MediaTypeProvider types);
 	
 	void setCacheControl(final String value);
 	
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ServletMimeTypes.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ServletMediaTypeProvider.java
similarity index 83%
rename from rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ServletMimeTypes.java
rename to rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ServletMediaTypeProvider.java
index 09d9c38..4e4fca5 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ServletMimeTypes.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/ServletMediaTypeProvider.java
@@ -21,19 +21,19 @@
 
 
 @NonNullByDefault
-public class ServletMimeTypes implements MimeTypes {
+public class ServletMediaTypeProvider implements MediaTypeProvider {
 	
 	
 	private final ServletContext servletContext;
 	
 	
-	public ServletMimeTypes(final ServletContext servletContext) {
+	public ServletMediaTypeProvider(final ServletContext servletContext) {
 		this.servletContext= servletContext;
 	}
 	
 	
 	@Override
-	public @Nullable String getMimeType(final String fileName) {
+	public @Nullable String getMediaTypeString(final String fileName) {
 		return this.servletContext.getMimeType(fileName);
 	}
 	
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/SimpleResourceHandler.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/SimpleResourceHandler.java
index ee3b02e..c552e02 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/SimpleResourceHandler.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/SimpleResourceHandler.java
@@ -32,29 +32,29 @@
 public class SimpleResourceHandler implements ResourceHandler {
 	
 	
-	private final MimeTypes defaultMimeTypes;
-	private @Nullable MimeTypes specialMimeTypes;
+	private final MediaTypeProvider defaultMediaTypes;
+	private @Nullable MediaTypeProvider specialMediaTypes;
 	
 	private @Nullable String cacheControl;
 	
 	
-	public SimpleResourceHandler(final MimeTypes mimeTypes) {
-		this.defaultMimeTypes= mimeTypes;
+	public SimpleResourceHandler(final MediaTypeProvider mediaTypes) {
+		this.defaultMediaTypes= mediaTypes;
 	}
 	
 	
 	@Override
-	public void setSpecialMimeTypes(final MimeTypes types) {
-		this.specialMimeTypes= types;
+	public void setSpecialMediaTypes(final MediaTypeProvider types) {
+		this.specialMediaTypes= types;
 	}
 	
-	private @Nullable String getMimeType(final String fileName) {
+	private @Nullable String getMediaType(final String fileName) {
 		String type= null;
-		if (this.specialMimeTypes != null) {
-			type= this.specialMimeTypes.getMimeType(fileName);
+		if (this.specialMediaTypes != null) {
+			type= this.specialMediaTypes.getMediaTypeString(fileName);
 		}
 		if (type == null) {
-			type= this.defaultMimeTypes.getMimeType(fileName);
+			type= this.defaultMediaTypes.getMediaTypeString(fileName);
 		}
 		return type;
 	}
@@ -71,9 +71,9 @@
 			in.available();
 			final byte[] buffer= new byte[1024];
 			
-			{	final String mimeType= getMimeType(file.getFileName().toString());
-				if (mimeType != null) {
-					resp.setContentType(mimeType);
+			{	final String mediaType= getMediaType(file.getFileName().toString());
+				if (mediaType != null) {
+					resp.setContentType(mediaType);
 				}
 			}
 			{	final String cacheControl= this.cacheControl;
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyRHelpUtils.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyRHelpUtils.java
index 71213d0..8d99120 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyRHelpUtils.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyRHelpUtils.java
@@ -23,25 +23,25 @@
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
 import org.eclipse.statet.jcommons.lang.Nullable;
 
-import org.eclipse.statet.rhelp.core.http.MimeTypes;
+import org.eclipse.statet.rhelp.core.http.MediaTypeProvider;
 import org.eclipse.statet.rhelp.core.http.ResourceHandler;
-import org.eclipse.statet.rhelp.core.http.ServletMimeTypes;
+import org.eclipse.statet.rhelp.core.http.ServletMediaTypeProvider;
 
 
 @NonNullByDefault
 public class JettyRHelpUtils {
 	
 	
-	public static MimeTypes getMimeTypes(final ServletContext context) {
-		return new ServletMimeTypes(context);
+	public static MediaTypeProvider getMediaTypes(final ServletContext context) {
+		return new ServletMediaTypeProvider(context);
 	}
 	
-	public static ResourceHandler newResourceHandler(final MimeTypes mimeTypes) {
-		return new JettyResourceHandler(mimeTypes);
+	public static ResourceHandler newResourceHandler(final MediaTypeProvider mediaTypes) {
+		return new JettyResourceHandler(mediaTypes);
 	}
 	
 	public static ResourceHandler newResourceHandler(final ServletContext context) {
-		return newResourceHandler(getMimeTypes(context));
+		return newResourceHandler(getMediaTypes(context));
 	}
 	
 	
diff --git a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyResourceHandler.java b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyResourceHandler.java
index 7cddc31..e83a7f0 100644
--- a/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyResourceHandler.java
+++ b/rhelp/org.eclipse.statet.rhelp.core/src/org/eclipse/statet/rhelp/core/http/jetty/JettyResourceHandler.java
@@ -36,7 +36,7 @@
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
 import org.eclipse.statet.jcommons.lang.Nullable;
 
-import org.eclipse.statet.rhelp.core.http.MimeTypes;
+import org.eclipse.statet.rhelp.core.http.MediaTypeProvider;
 import org.eclipse.statet.rhelp.core.http.ResourceHandler;
 
 
@@ -47,13 +47,13 @@
 	private static class JettyMimeTypes extends org.eclipse.jetty.http.MimeTypes {
 		
 		
-		private final MimeTypes defaultTypes;
+		private final MediaTypeProvider defaultMediaTypes;
 		
-		private @Nullable MimeTypes specialTypes;
+		private @Nullable MediaTypeProvider specialMediaTypes;
 		
 		
-		public JettyMimeTypes(final MimeTypes mimeTypes) {
-			this.defaultTypes= mimeTypes;
+		public JettyMimeTypes(final MediaTypeProvider mimeTypes) {
+			this.defaultMediaTypes= mimeTypes;
 		}
 		
 		@Override
@@ -63,11 +63,11 @@
 				filename= filename.substring(idx + 1);
 			}
 			String type= null;
-			if (this.specialTypes != null) {
-				type= this.specialTypes.getMimeType(filename);
+			if (this.specialMediaTypes != null) {
+				type= this.specialMediaTypes.getMediaTypeString(filename);
 			}
 			if (type == null) {
-				type= this.defaultTypes.getMimeType(filename);
+				type= this.defaultMediaTypes.getMediaTypeString(filename);
 			}
 			if (type == null) {
 				type= super.getMimeByExtension(filename);
@@ -78,19 +78,19 @@
 	}
 	
 	
-	private final JettyMimeTypes mimeTypes;
+	private final JettyMimeTypes mediaTypes;
 	
 	
-	public JettyResourceHandler(final MimeTypes defaultTypes) {
-		this.mimeTypes= new JettyMimeTypes(defaultTypes);
-		setContentFactory(new ResourceContentFactory(this, this.mimeTypes,
+	public JettyResourceHandler(final MediaTypeProvider defaultTypes) {
+		this.mediaTypes= new JettyMimeTypes(defaultTypes);
+		setContentFactory(new ResourceContentFactory(this, this.mediaTypes,
 				new CompressedContentFormat[0] ));
 	}
 	
 	
 	@Override
-	public void setSpecialMimeTypes(final MimeTypes types) {
-		this.mimeTypes.specialTypes= types;
+	public void setSpecialMediaTypes(final MediaTypeProvider types) {
+		this.mediaTypes.specialMediaTypes= types;
 	}
 	
 	@Override
diff --git a/rhelp/org.eclipse.statet.rhelp.server/pom.xml b/rhelp/org.eclipse.statet.rhelp.server/pom.xml
index 3b756a5..f3b3185 100644
--- a/rhelp/org.eclipse.statet.rhelp.server/pom.xml
+++ b/rhelp/org.eclipse.statet.rhelp.server/pom.xml
@@ -50,6 +50,12 @@
 			<version>4.1.0-SNAPSHOT</version>
 		</dependency>
 		
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-client</artifactId>
+			<scope>test</scope>
+		</dependency>
+		
 	</dependencies>
 	
 	<build>
diff --git a/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/AbstractDefaultAppTest.java b/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/AbstractDefaultAppTest.java
new file mode 100644
index 0000000..262e47c
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/AbstractDefaultAppTest.java
@@ -0,0 +1,90 @@
+/*=============================================================================#
+ # Copyright (c) 2020 Stephan Wahlbrink <sw@wahlbrink.eu> and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rhelp.server;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.jcommons.status.Status;
+
+import org.eclipse.statet.rhelp.core.REnvHelp;
+import org.eclipse.statet.rhelp.core.RHelpManager;
+import org.eclipse.statet.rj.renv.core.REnv;
+import org.eclipse.statet.rj.renv.core.REnvConfiguration;
+import org.eclipse.statet.rj.renv.core.REnvManager;
+
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment= WebEnvironment.RANDOM_PORT)
+@Import(ContextConfiguration.class)
+@NonNullByDefault
+public abstract class AbstractDefaultAppTest {
+	
+	
+	@Autowired
+	protected @Nullable REnvManager rEnvManager;
+	
+	@Autowired
+	protected @Nullable RHelpManager rHelpManager;
+	
+	
+	public AbstractDefaultAppTest() {
+	}
+	
+	
+	@SuppressWarnings("null")
+	protected static <T> T assumeNotNull(final @Nullable T value) {
+		assumeTrue(value != null);
+		return value;
+	}
+	
+	@SuppressWarnings("null")
+	protected static REnv assumeREnvValid(final @Nullable REnv rEnv) {
+		assumeTrue(rEnv != null);
+		final REnvConfiguration rEnvConfiguration= rEnv.get(REnvConfiguration.class);
+		assumeTrue(rEnvConfiguration != null
+				&& rEnvConfiguration.getValidationStatus().getSeverity() == Status.OK );
+		return rEnv;
+	}
+	
+	protected void assumeRHelpAvailable(final String envId) throws InterruptedException {
+		final REnvManager rEnvManager= assumeNotNull(this.rEnvManager);
+		final REnv rEnv= assumeREnvValid(rEnvManager.get(envId, null));
+		
+		final RHelpManager rHelpManager= assumeNotNull(this.rHelpManager);
+		final long tStart= System.nanoTime();
+		final long tEnd= tStart + SECONDS.toNanos(5);
+		while (tStart < tEnd) {
+			final REnvHelp rEnvHelp= rHelpManager.getHelp(rEnv);
+			if (rEnvHelp != null) {
+				rEnvHelp.unlock();
+				return;
+			}
+			Thread.sleep(500);
+		}
+		assumeTrue(false, String.format("Help for R env '%1$s' available.", envId));
+	}
+	
+}
diff --git a/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/ApplicationTests.java b/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/ApplicationTests.java
index 0e5fd42..20c1367 100644
--- a/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/ApplicationTests.java
+++ b/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/ApplicationTests.java
@@ -17,21 +17,14 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import java.time.Duration;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.context.annotation.Import;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
-import org.eclipse.statet.jcommons.lang.Nullable;
 import org.eclipse.statet.jcommons.runtime.AppEnvironment;
 import org.eclipse.statet.jcommons.runtime.CommonsRuntime;
 import org.eclipse.statet.jcommons.status.Status;
@@ -43,18 +36,8 @@
 import org.eclipse.statet.rj.renv.core.REnvManager;
 
 
-@ExtendWith(SpringExtension.class)
-@SpringBootTest
-@Import(ContextConfiguration.class)
 @NonNullByDefault
-public class ApplicationTests {
-	
-	
-	@Autowired
-	private @Nullable REnvManager rEnvManager;
-	
-	@Autowired
-	private @Nullable RHelpManager rHelpManager;
+public class ApplicationTests extends AbstractDefaultAppTest {
 	
 	
 	@Test
@@ -94,12 +77,32 @@
 	
 	@Test
 	@EnabledIfEnvironmentVariable(named = "STATET_TEST_FILES", matches = ".+")
-	public void RHelp_available() {
+	public void RHelp_loadAvailable() {
 		final REnvManager rEnvManager= assumeNotNull(this.rEnvManager);
 		final REnv rEnv= assumeREnvValid(rEnvManager.get("default", null));
 		
 		final RHelpManager rHelpManager= assumeNotNull(this.rHelpManager);
 		
+		assertTimeoutPreemptively(Duration.ofSeconds(10),
+				() -> {
+					while (true) {
+						final REnvHelp rEnvHelp= rHelpManager.getHelp(rEnv);
+						if (rEnvHelp != null) {
+							rEnvHelp.unlock();
+							return;
+						}
+					}
+				});
+	}
+	
+	@Test
+	@EnabledIfEnvironmentVariable(named = "STATET_TEST_FILES", matches = ".+")
+	public void RHelp_createNew() {
+		final REnvManager rEnvManager= assumeNotNull(this.rEnvManager);
+		final REnv rEnv= assumeREnvValid(rEnvManager.get("new", null));
+		
+		final RHelpManager rHelpManager= assumeNotNull(this.rHelpManager);
+		
 		assertTimeoutPreemptively(Duration.ofMinutes(10),
 				() -> {
 					while (true) {
@@ -113,19 +116,4 @@
 	}
 	
 	
-	@SuppressWarnings("null")
-	private static <T> T assumeNotNull(final @Nullable T value) {
-		assumeTrue(value != null);
-		return value;
-	}
-	
-	@SuppressWarnings("null")
-	private static REnv assumeREnvValid(final @Nullable REnv rEnv) {
-		assumeTrue(rEnv != null);
-		final REnvConfiguration rEnvConfiguration= rEnv.get(REnvConfiguration.class);
-		assumeTrue(rEnvConfiguration != null
-				&& rEnvConfiguration.getValidationStatus().getSeverity() == Status.OK );
-		return rEnv;
-	}
-	
 }
diff --git a/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/HttpAccesssTests.java b/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/HttpAccesssTests.java
new file mode 100644
index 0000000..6d8191f
--- /dev/null
+++ b/rhelp/org.eclipse.statet.rhelp.server/src/test/java/org/eclipse/statet/rhelp/server/HttpAccesssTests.java
@@ -0,0 +1,107 @@
+/*=============================================================================#
+ # Copyright (c) 2020 Stephan Wahlbrink <sw@wahlbrink.eu> and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rhelp.server;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.eclipse.jetty.client.HttpClient;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.util.StreamUtils;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.internal.rhelp.core.DataStream;
+import org.eclipse.statet.internal.rhelp.core.REnvHelpImpl;
+import org.eclipse.statet.internal.rhelp.core.SerUtil;
+import org.eclipse.statet.internal.rhelp.core.server.JettyREnvHelpAccess;
+import org.eclipse.statet.internal.rhelp.core.server.ServerApi;
+import org.eclipse.statet.rhelp.core.http.jetty.JettyRHelpUtils;
+
+
+@NonNullByDefault
+public class HttpAccesssTests extends AbstractDefaultAppTest {
+	
+	
+	protected static class TestHelpAccess extends JettyREnvHelpAccess {
+		
+		
+		public TestHelpAccess(final URI url, final HttpClient httpClient) throws Exception {
+			super(url, httpClient);
+		}
+		
+		
+		public byte @Nullable [] loadREnvHelpData(
+				final long currentStamp) throws Exception {
+			try (final InputStream in= getDataStream(
+					createUrl(createPath(ServerApi.BASIC_DATA)),
+					ServerApi.createETag(currentStamp) )) {
+				if (in == null) {
+					return null;
+				}
+				return StreamUtils.copyToByteArray(in);
+			}
+		}
+		
+	}
+	
+	
+	@LocalServerPort
+	private int port;
+	
+	
+	public HttpAccesssTests() {
+	}
+	
+	
+	private HttpClient getHttpClient() {
+		final HttpClient httpClient= new HttpClient();
+		httpClient.setExecutor(JettyRHelpUtils.getExecutor());
+		httpClient.setAddressResolutionTimeout(10000);
+		httpClient.setConnectTimeout(10000);
+		return httpClient;
+	}
+	
+	private URI getHelpUrl(final String envId) throws URISyntaxException {
+		return new URI("http", null, "localhost", this.port, "/" + envId, null, null);
+	}
+	
+	
+	@Test
+	@EnabledIfEnvironmentVariable(named = "STATET_TEST_FILES", matches = ".+")
+	public void loadBasicData() throws Exception {
+		assumeRHelpAvailable("default");
+		
+		final TestHelpAccess clientSupport= new TestHelpAccess(
+				getHelpUrl("default"), getHttpClient() );
+		final byte[] basicDataSerialized= clientSupport.loadREnvHelpData(REnvHelpImpl.NOT_AVAILABLE_STAMP);
+		
+		assertNotNull(basicDataSerialized);
+		
+		final DataStream in= DataStream.get(new ByteArrayInputStream(basicDataSerialized));
+		Assertions.assertEquals(SerUtil.CURRENT_VERSION, in.readVersion());
+	}
+	
+	
+}
diff --git a/rhelp/pom.xml b/rhelp/pom.xml
index 65beeae..9e96aaf 100644
--- a/rhelp/pom.xml
+++ b/rhelp/pom.xml
@@ -32,6 +32,7 @@
 	
 	<modules>
 		<module>org.eclipse.statet.rhelp.core</module>
+		<module>org.eclipse.statet.rhelp.core-tests</module>
 		
 		<module>org.eclipse.statet.rhelp.server</module>