Merge lp:~jderose/ubuntu/saucy/couchdb/1.4.0 into lp:ubuntu/saucy/couchdb

Proposed by Chad Miller
Status: Merged
Merge reported by: Robie Basak
Merged at revision: not available
Proposed branch: lp:~jderose/ubuntu/saucy/couchdb/1.4.0
Merge into: lp:ubuntu/saucy/couchdb
Diff against target: 173949 lines (+110026/-36696)
496 files modified
.pc/applied-patches (+0/-8)
.pc/couchdb_own_rundir.patch/etc/init/couchdb.tpl.in (+0/-156)
.pc/couchdb_sighup.patch/bin/couchdb.tpl.in (+0/-335)
.pc/force-reload.patch/etc/init/couchdb.tpl.in (+0/-156)
.pc/improve_parsing_of_mochiweb_relative_paths.patch/src/mochiweb/mochiweb_util.erl (+0/-973)
.pc/improve_script_url_validation.patch/share/www/script/couch_test_runner.js (+0/-472)
.pc/include_a_comment_before_jsonp_output.patch/src/couchdb/couch_httpd.erl (+0/-1081)
.pc/logrotate_as_couchdb.patch/etc/logrotate.d/couchdb.tpl.in (+0/-9)
.pc/wait_for_couchdb_stop.patch/etc/init/couchdb.tpl.in (+0/-157)
AUTHORS (+6/-0)
BUGS (+5/-3)
CHANGES (+0/-874)
DEVELOPERS (+128/-22)
INSTALL (+171/-35)
INSTALL.Unix (+80/-44)
INSTALL.Windows (+72/-21)
LICENSE (+489/-12)
Makefile.am (+63/-59)
Makefile.in (+329/-188)
NEWS (+0/-418)
NOTICE (+98/-10)
README (+0/-83)
README.rst (+95/-0)
THANKS (+55/-4)
acinclude.m4 (+1/-1)
aclocal.m4 (+962/-140)
bin/Makefile.am (+59/-30)
bin/Makefile.in (+212/-140)
bin/couch-config.tpl.in (+1/-1)
bin/couchdb.1 (+2/-2)
bin/couchdb.bat.tpl.in (+1/-1)
bin/couchdb.tpl.in (+34/-5)
build-aux/config.guess (+343/-293)
build-aux/config.sub (+294/-103)
build-aux/depcomp (+207/-83)
build-aux/dist-error (+28/-0)
build-aux/install-sh (+141/-121)
build-aux/ltmain.sh (+1640/-749)
build-aux/missing (+29/-65)
build-aux/sphinx-build (+67/-0)
build-aux/sphinx-touch (+24/-0)
config.h.in (+48/-7)
configure (+8546/-8152)
configure.ac (+356/-214)
debian/README.Debian (+0/-26)
debian/README.source (+0/-20)
debian/changelog (+41/-0)
debian/compat (+1/-1)
debian/control (+39/-19)
debian/couchdb-bin.install (+4/-1)
debian/couchdb-bin.postrm (+0/-16)
debian/couchdb-common.install (+3/-0)
debian/couchdb.install (+0/-2)
debian/couchdb.lintian-overrides (+2/-1)
debian/couchdb.postinst (+6/-0)
debian/couchdb.postrm (+0/-5)
debian/couchdb.upstart (+19/-0)
debian/patches/couchdb_own_rundir.patch (+0/-20)
debian/patches/couchdb_sighup.patch (+0/-22)
debian/patches/force-reload.patch (+0/-21)
debian/patches/improve_parsing_of_mochiweb_relative_paths.patch (+0/-40)
debian/patches/improve_script_url_validation.patch (+0/-26)
debian/patches/include_a_comment_before_jsonp_output.patch (+0/-20)
debian/patches/logrotate_as_couchdb.patch (+0/-16)
debian/patches/series (+0/-8)
debian/patches/wait_for_couchdb_stop.patch (+0/-30)
debian/rules (+20/-51)
debian/watch (+1/-1)
etc/Makefile.in (+218/-96)
etc/couchdb/Makefile.am (+10/-3)
etc/couchdb/Makefile.in (+122/-40)
etc/couchdb/default.ini.tpl.in (+55/-12)
etc/couchdb/local.ini (+13/-4)
etc/default/Makefile.in (+76/-24)
etc/init/Makefile.in (+76/-24)
etc/init/couchdb.tpl.in (+6/-15)
etc/launchd/Makefile.in (+76/-24)
etc/logrotate.d/Makefile.in (+76/-24)
etc/logrotate.d/couchdb.tpl.in (+0/-2)
etc/windows/Makefile.in (+76/-24)
etc/windows/couchdb.iss.tpl (+8/-4)
license.skip (+59/-36)
m4/ac_check_curl.m4 (+0/-69)
m4/ac_check_icu.m4 (+0/-74)
m4/libtool.m4 (+762/-355)
m4/ltversion.m4 (+6/-6)
m4/pkg.m4 (+0/-157)
share/Makefile.am (+20/-1)
share/Makefile.in (+408/-100)
share/doc/Makefile.am (+14/-0)
share/doc/Makefile.in (+644/-0)
share/doc/build/Makefile.am (+329/-0)
share/doc/build/Makefile.in (+752/-0)
share/doc/build/html/_sources/api-basics.txt (+463/-0)
share/doc/build/html/_sources/api/authn.txt (+41/-0)
share/doc/build/html/_sources/api/configuration.txt (+297/-0)
share/doc/build/html/_sources/api/database.txt (+1471/-0)
share/doc/build/html/_sources/api/design.txt (+1264/-0)
share/doc/build/html/_sources/api/documents.txt (+973/-0)
share/doc/build/html/_sources/api/local.txt (+169/-0)
share/doc/build/html/_sources/api/misc.txt (+867/-0)
share/doc/build/html/_sources/api/reference.txt (+42/-0)
share/doc/build/html/_sources/changelog.txt (+1489/-0)
share/doc/build/html/_sources/changes.txt (+227/-0)
share/doc/build/html/_sources/config_reference.txt (+330/-0)
share/doc/build/html/_sources/configuring.txt (+629/-0)
share/doc/build/html/_sources/contributing.txt (+167/-0)
share/doc/build/html/_sources/ddocs.txt (+751/-0)
share/doc/build/html/_sources/index.txt (+46/-0)
share/doc/build/html/_sources/intro.txt (+309/-0)
share/doc/build/html/_sources/json-structure.txt (+825/-0)
share/doc/build/html/_sources/query-servers.txt (+436/-0)
share/doc/build/html/_sources/replication.txt (+95/-0)
share/doc/build/html/_sources/replicator.txt (+383/-0)
share/doc/build/html/_static/basic.css (+540/-0)
share/doc/build/html/_static/default.css (+256/-0)
share/doc/build/html/_static/doctools.js (+247/-0)
share/doc/build/html/_static/jquery.js (+154/-0)
share/doc/build/html/_static/pygments.css (+62/-0)
share/doc/build/html/_static/rtd.css (+795/-0)
share/doc/build/html/_static/searchtools.js (+560/-0)
share/doc/build/html/_static/sidebar.js (+151/-0)
share/doc/build/html/_static/underscore.js (+23/-0)
share/doc/build/html/_static/websupport.js (+808/-0)
share/doc/build/html/api-basics.html (+556/-0)
share/doc/build/html/api/authn.html (+222/-0)
share/doc/build/html/api/configuration.html (+467/-0)
share/doc/build/html/api/database.html (+1646/-0)
share/doc/build/html/api/design.html (+1384/-0)
share/doc/build/html/api/documents.html (+1136/-0)
share/doc/build/html/api/local.html (+363/-0)
share/doc/build/html/api/misc.html (+1222/-0)
share/doc/build/html/api/reference.html (+273/-0)
share/doc/build/html/changelog.html (+2043/-0)
share/doc/build/html/changes.html (+414/-0)
share/doc/build/html/config_reference.html (+743/-0)
share/doc/build/html/configuring.html (+682/-0)
share/doc/build/html/ddocs.html (+976/-0)
share/doc/build/html/genindex.html (+360/-0)
share/doc/build/html/index.html (+316/-0)
share/doc/build/html/intro.html (+423/-0)
share/doc/build/html/json-structure.html (+1278/-0)
share/doc/build/html/query-servers.html (+739/-0)
share/doc/build/html/replication.html (+247/-0)
share/doc/build/html/replicator.html (+503/-0)
share/doc/build/html/search.html (+177/-0)
share/doc/build/html/searchindex.js (+1/-0)
share/doc/build/texinfo/CouchDB.info (+16106/-0)
share/doc/src/api-basics.rst (+463/-0)
share/doc/src/api/authn.rst (+41/-0)
share/doc/src/api/configuration.rst (+297/-0)
share/doc/src/api/database.rst (+1471/-0)
share/doc/src/api/design.rst (+1264/-0)
share/doc/src/api/documents.rst (+973/-0)
share/doc/src/api/local.rst (+169/-0)
share/doc/src/api/misc.rst (+867/-0)
share/doc/src/api/reference.rst (+42/-0)
share/doc/src/changelog.rst (+1489/-0)
share/doc/src/changes.rst (+227/-0)
share/doc/src/conf.py (+88/-0)
share/doc/src/config_reference.rst (+330/-0)
share/doc/src/configuring.rst (+629/-0)
share/doc/src/contributing.rst (+167/-0)
share/doc/src/ddocs.rst (+751/-0)
share/doc/src/index.rst (+46/-0)
share/doc/src/intro.rst (+309/-0)
share/doc/src/json-structure.rst (+825/-0)
share/doc/src/query-servers.rst (+436/-0)
share/doc/src/replication.rst (+95/-0)
share/doc/src/replicator.rst (+383/-0)
share/doc/static/rtd.css (+795/-0)
share/doc/templates/help.html (+24/-0)
share/doc/templates/searchbox.html (+31/-0)
share/doc/templates/utilities.html (+22/-0)
share/server/filter.js (+1/-1)
share/server/loop.js (+5/-3)
share/server/render.js (+17/-5)
share/server/util.js (+18/-9)
share/server/validate.js (+4/-1)
share/server/views.js (+2/-1)
share/www/_sidebar.html (+7/-6)
share/www/config.html (+5/-5)
share/www/couch_tests.html (+6/-6)
share/www/custom_test.html (+7/-7)
share/www/database.html (+14/-11)
share/www/dialog/_delete_database.html (+4/-2)
share/www/document.html (+9/-9)
share/www/index.html (+6/-6)
share/www/replicator.html (+4/-4)
share/www/script/couch.js (+52/-5)
share/www/script/couch_test_runner.js (+3/-1)
share/www/script/couch_tests.js (+18/-1)
share/www/script/futon.browse.js (+46/-6)
share/www/script/futon.js (+30/-0)
share/www/script/jquery.couch.js (+10/-6)
share/www/script/jquery.js (+5655/-5164)
share/www/script/jquery.suggest.js (+0/-2)
share/www/script/replicator_db_inc.js (+96/-0)
share/www/script/test/attachment_names.js (+0/-2)
share/www/script/test/attachment_ranges.js (+5/-0)
share/www/script/test/attachments.js (+27/-0)
share/www/script/test/attachments_multipart.js (+32/-29)
share/www/script/test/changes.js (+139/-44)
share/www/script/test/config.js (+49/-1)
share/www/script/test/content_negotiation.js (+2/-2)
share/www/script/test/cookie_auth.js (+25/-20)
share/www/script/test/etags_views.js (+2/-2)
share/www/script/test/form_submit.js (+0/-1)
share/www/script/test/list_views.js (+37/-0)
share/www/script/test/oauth.js (+2/-1)
share/www/script/test/reader_acl.js (+7/-0)
share/www/script/test/replication.js (+11/-0)
share/www/script/test/replicator_db.js (+0/-1547)
share/www/script/test/replicator_db_bad_rep_id.js (+77/-0)
share/www/script/test/replicator_db_by_doc_id.js (+99/-0)
share/www/script/test/replicator_db_compact_rep_db.js (+119/-0)
share/www/script/test/replicator_db_continuous.js (+137/-0)
share/www/script/test/replicator_db_credential_delegation.js (+149/-0)
share/www/script/test/replicator_db_field_validation.js (+178/-0)
share/www/script/test/replicator_db_filtered.js (+105/-0)
share/www/script/test/replicator_db_identical.js (+87/-0)
share/www/script/test/replicator_db_identical_continuous.js (+132/-0)
share/www/script/test/replicator_db_invalid_filter.js (+115/-0)
share/www/script/test/replicator_db_security.js (+12/-8)
share/www/script/test/replicator_db_simple.js (+114/-0)
share/www/script/test/replicator_db_successive.js (+127/-0)
share/www/script/test/replicator_db_survives.js (+126/-0)
share/www/script/test/replicator_db_swap_rep_db.js (+170/-0)
share/www/script/test/replicator_db_update_security.js (+92/-0)
share/www/script/test/replicator_db_user_ctx.js (+272/-0)
share/www/script/test/replicator_db_write_auth.js (+102/-0)
share/www/script/test/rev_stemming.js (+3/-0)
share/www/script/test/rewrite.js (+173/-119)
share/www/script/test/security_validation.js (+2/-2)
share/www/script/test/show_documents.js (+2/-2)
share/www/script/test/update_documents.js (+56/-2)
share/www/script/test/users_db.js (+38/-0)
share/www/script/test/users_db_security.js (+111/-9)
share/www/script/test/utf8.js (+1/-0)
share/www/script/test/uuids.js (+26/-1)
share/www/script/test/view_compaction.js (+10/-10)
share/www/script/test/view_multi_key_all_docs.js (+4/-0)
share/www/script/test/view_multi_key_design.js (+4/-0)
share/www/script/test/view_multi_key_temp.js (+3/-0)
share/www/session.html (+6/-6)
share/www/spec/run.html (+1/-0)
share/www/status.html (+4/-4)
share/www/style/layout.css (+4/-0)
share/www/verify_install.html (+8/-7)
src/Makefile.am (+12/-1)
src/Makefile.in (+163/-59)
src/couch_dbupdates/Makefile.am (+33/-0)
src/couch_dbupdates/Makefile.in (+519/-0)
src/couch_dbupdates/src/couch_dbupdates.app.src (+11/-0)
src/couch_dbupdates/src/couch_dbupdates.erl (+46/-0)
src/couch_dbupdates/src/couch_dbupdates_httpd.erl (+69/-0)
src/couch_index/Makefile.am (+40/-0)
src/couch_index/Makefile.in (+525/-0)
src/couch_index/src/couch_index.app.src (+22/-0)
src/couch_index/src/couch_index.erl (+340/-0)
src/couch_index/src/couch_index_api.erl (+54/-0)
src/couch_index/src/couch_index_compactor.erl (+114/-0)
src/couch_index/src/couch_index_server.erl (+201/-0)
src/couch_index/src/couch_index_updater.erl (+200/-0)
src/couch_index/src/couch_index_util.erl (+78/-0)
src/couch_mrview/Makefile.am (+73/-0)
src/couch_mrview/Makefile.in (+582/-0)
src/couch_mrview/include/couch_mrview.hrl (+80/-0)
src/couch_mrview/src/couch_mrview.app.src (+28/-0)
src/couch_mrview/src/couch_mrview.erl (+387/-0)
src/couch_mrview/src/couch_mrview_cleanup.erl (+47/-0)
src/couch_mrview/src/couch_mrview_compactor.erl (+178/-0)
src/couch_mrview/src/couch_mrview_http.erl (+378/-0)
src/couch_mrview/src/couch_mrview_index.erl (+162/-0)
src/couch_mrview/src/couch_mrview_show.erl (+368/-0)
src/couch_mrview/src/couch_mrview_test_util.erl (+91/-0)
src/couch_mrview/src/couch_mrview_updater.erl (+282/-0)
src/couch_mrview/src/couch_mrview_util.erl (+802/-0)
src/couch_mrview/test/01-load.t (+34/-0)
src/couch_mrview/test/02-map-views.t (+131/-0)
src/couch_mrview/test/03-red-views.t (+78/-0)
src/couch_mrview/test/04-index-info.t (+54/-0)
src/couch_mrview/test/05-collation.t (+163/-0)
src/couch_mrview/test/06-all-docs.t (+127/-0)
src/couch_mrview/test/07-compact-swap.t (+57/-0)
src/couch_replicator/Makefile.am (+77/-0)
src/couch_replicator/Makefile.in (+586/-0)
src/couch_replicator/src/couch_replicator.app.src (+33/-0)
src/couch_replicator/src/couch_replicator.erl (+955/-0)
src/couch_replicator/src/couch_replicator.hrl (+30/-0)
src/couch_replicator/src/couch_replicator_api_wrap.erl (+780/-0)
src/couch_replicator/src/couch_replicator_api_wrap.hrl (+36/-0)
src/couch_replicator/src/couch_replicator_httpc.erl (+297/-0)
src/couch_replicator/src/couch_replicator_httpc_pool.erl (+138/-0)
src/couch_replicator/src/couch_replicator_httpd.erl (+66/-0)
src/couch_replicator/src/couch_replicator_job_sup.erl (+31/-0)
src/couch_replicator/src/couch_replicator_js_functions.hrl (+151/-0)
src/couch_replicator/src/couch_replicator_manager.erl (+703/-0)
src/couch_replicator/src/couch_replicator_notifier.erl (+57/-0)
src/couch_replicator/src/couch_replicator_utils.erl (+388/-0)
src/couch_replicator/src/couch_replicator_worker.erl (+515/-0)
src/couch_replicator/test/01-load.t (+37/-0)
src/couch_replicator/test/02-httpc-pool.t (+250/-0)
src/couch_replicator/test/03-replication-compact.t (+488/-0)
src/couch_replicator/test/04-replication-large-atts.t (+267/-0)
src/couch_replicator/test/05-replication-many-leaves.t (+294/-0)
src/couch_replicator/test/06-doc-missing-stubs.t (+304/-0)
src/couchdb/Makefile.am (+10/-39)
src/couchdb/Makefile.in (+210/-120)
src/couchdb/couch.app.tpl.in (+1/-3)
src/couchdb/couch_api_wrap.erl (+0/-779)
src/couchdb/couch_api_wrap.hrl (+0/-36)
src/couchdb/couch_api_wrap_httpc.erl (+0/-286)
src/couchdb/couch_app.erl (+1/-1)
src/couchdb/couch_auth_cache.erl (+25/-10)
src/couchdb/couch_changes.erl (+19/-7)
src/couchdb/couch_compaction_daemon.erl (+9/-10)
src/couchdb/couch_config.erl (+2/-2)
src/couchdb/couch_config_writer.erl (+1/-1)
src/couchdb/couch_db.erl (+47/-25)
src/couchdb/couch_db.hrl (+13/-29)
src/couchdb/couch_db_update_notifier.erl (+11/-2)
src/couchdb/couch_db_updater.erl (+19/-17)
src/couchdb/couch_doc.erl (+64/-10)
src/couchdb/couch_ejson_compare.erl (+12/-1)
src/couchdb/couch_file.erl (+27/-3)
src/couchdb/couch_httpc_pool.erl (+0/-138)
src/couchdb/couch_httpd.erl (+122/-90)
src/couchdb/couch_httpd_auth.erl (+31/-19)
src/couchdb/couch_httpd_cors.erl (+349/-0)
src/couchdb/couch_httpd_db.erl (+118/-280)
src/couchdb/couch_httpd_external.erl (+11/-7)
src/couchdb/couch_httpd_misc_handlers.erl (+77/-13)
src/couchdb/couch_httpd_oauth.erl (+10/-9)
src/couchdb/couch_httpd_replicator.erl (+0/-66)
src/couchdb/couch_httpd_rewrite.erl (+18/-5)
src/couchdb/couch_httpd_show.erl (+0/-407)
src/couchdb/couch_httpd_vhost.erl (+34/-26)
src/couchdb/couch_httpd_view.erl (+0/-777)
src/couchdb/couch_js_functions.hrl (+11/-142)
src/couchdb/couch_log.erl (+61/-10)
src/couchdb/couch_os_daemons.erl (+11/-1)
src/couchdb/couch_os_process.erl (+1/-1)
src/couchdb/couch_passwords.erl (+119/-0)
src/couchdb/couch_primary_sup.erl (+3/-3)
src/couchdb/couch_rep_sup.erl (+0/-31)
src/couchdb/couch_replication_manager.erl (+0/-694)
src/couchdb/couch_replication_notifier.erl (+0/-57)
src/couchdb/couch_replicator.erl (+0/-952)
src/couchdb/couch_replicator.hrl (+0/-30)
src/couchdb/couch_replicator_utils.erl (+0/-382)
src/couchdb/couch_replicator_worker.erl (+0/-515)
src/couchdb/couch_server.erl (+55/-30)
src/couchdb/couch_stream.erl (+13/-8)
src/couchdb/couch_users_db.erl (+27/-9)
src/couchdb/couch_util.erl (+61/-8)
src/couchdb/couch_uuids.erl (+9/-1)
src/couchdb/couch_view.erl (+0/-437)
src/couchdb/couch_view_compactor.erl (+0/-152)
src/couchdb/couch_view_group.erl (+0/-699)
src/couchdb/couch_view_updater.erl (+0/-283)
src/couchdb/couch_work_queue.erl (+1/-1)
src/couchdb/priv/Makefile.am (+43/-13)
src/couchdb/priv/Makefile.in (+313/-215)
src/couchdb/priv/couch_ejson_compare/couch_ejson_compare.c (+11/-10)
src/couchdb/priv/couch_js/help.h (+4/-2)
src/couchdb/priv/couch_js/http.c (+63/-3)
src/couchdb/priv/couch_js/http.h (+3/-0)
src/couchdb/priv/couch_js/sm170.c (+50/-30)
src/couchdb/priv/couch_js/sm180.c (+50/-30)
src/couchdb/priv/couch_js/sm185.c (+58/-28)
src/couchdb/priv/couch_js/util.c (+79/-37)
src/couchdb/priv/couch_js/util.h (+6/-4)
src/couchdb/priv/couchjs.1 (+8/-4)
src/ejson/Makefile.in (+183/-98)
src/ejson/ejson.erl (+2/-0)
src/ejson/yajl/yajl_encode.c (+7/-0)
src/erlang-oauth/Makefile.am (+2/-13)
src/erlang-oauth/Makefile.in (+114/-49)
src/erlang-oauth/oauth.erl (+276/-68)
src/erlang-oauth/oauth_hmac_sha1.erl (+0/-11)
src/erlang-oauth/oauth_http.erl (+0/-22)
src/erlang-oauth/oauth_plaintext.erl (+0/-10)
src/erlang-oauth/oauth_rsa_sha1.erl (+0/-30)
src/erlang-oauth/oauth_unix.erl (+0/-16)
src/erlang-oauth/oauth_uri.erl (+0/-100)
src/etap/Makefile.am (+2/-18)
src/etap/Makefile.in (+114/-54)
src/etap/etap.erl (+273/-76)
src/etap/etap_application.erl (+0/-72)
src/etap/etap_can.erl (+0/-79)
src/etap/etap_exception.erl (+0/-66)
src/etap/etap_process.erl (+0/-42)
src/etap/etap_report.erl (+0/-343)
src/etap/etap_request.erl (+0/-89)
src/etap/etap_string.erl (+0/-47)
src/etap/etap_web.erl (+0/-65)
src/ibrowse/Makefile.in (+112/-36)
src/ibrowse/ibrowse.app.in (+4/-10)
src/ibrowse/ibrowse.erl (+158/-92)
src/ibrowse/ibrowse_http_client.erl (+175/-109)
src/ibrowse/ibrowse_lb.erl (+54/-37)
src/ibrowse/ibrowse_lib.erl (+62/-12)
src/ibrowse/ibrowse_test.erl (+122/-10)
src/mochiweb/Makefile.am (+0/-1)
src/mochiweb/Makefile.in (+112/-37)
src/mochiweb/mochifmt.erl (+1/-1)
src/mochiweb/mochifmt_records.erl (+10/-6)
src/mochiweb/mochifmt_std.erl (+12/-9)
src/mochiweb/mochiglobal.erl (+2/-2)
src/mochiweb/mochihex.erl (+1/-4)
src/mochiweb/mochijson.erl (+1/-3)
src/mochiweb/mochijson2.erl (+52/-12)
src/mochiweb/mochilists.erl (+1/-1)
src/mochiweb/mochilogfile2.erl (+1/-1)
src/mochiweb/mochinum.erl (+1/-1)
src/mochiweb/mochitemp.erl (+2/-1)
src/mochiweb/mochiutf8.erl (+4/-3)
src/mochiweb/mochiweb.app.in (+5/-28)
src/mochiweb/mochiweb.app.src (+0/-9)
src/mochiweb/mochiweb.erl (+19/-27)
src/mochiweb/mochiweb_acceptor.erl (+7/-4)
src/mochiweb/mochiweb_charref.erl (+2131/-256)
src/mochiweb/mochiweb_cookies.erl (+29/-7)
src/mochiweb/mochiweb_cover.erl (+1/-1)
src/mochiweb/mochiweb_echo.erl (+9/-6)
src/mochiweb/mochiweb_headers.erl (+125/-4)
src/mochiweb/mochiweb_html.erl (+100/-32)
src/mochiweb/mochiweb_http.erl (+41/-67)
src/mochiweb/mochiweb_io.erl (+1/-4)
src/mochiweb/mochiweb_mime.erl (+360/-39)
src/mochiweb/mochiweb_multipart.erl (+73/-25)
src/mochiweb/mochiweb_request.erl (+299/-192)
src/mochiweb/mochiweb_request_tests.erl (+120/-1)
src/mochiweb/mochiweb_response.erl (+27/-19)
src/mochiweb/mochiweb_socket.erl (+7/-8)
src/mochiweb/mochiweb_socket_server.erl (+33/-47)
src/mochiweb/mochiweb_util.erl (+11/-5)
src/mochiweb/reloader.erl (+2/-2)
src/snappy/Makefile.am (+3/-3)
src/snappy/Makefile.in (+168/-83)
src/snappy/google-snappy/config.h.in (+33/-38)
src/snappy/google-snappy/snappy-sinksource.cc (+0/-1)
src/snappy/google-snappy/snappy-sinksource.h (+1/-0)
src/snappy/google-snappy/snappy-stubs-internal.h (+99/-5)
src/snappy/google-snappy/snappy.cc (+152/-62)
src/snappy/google-snappy/snappy.h (+2/-2)
src/snappy/snappy.app.in (+1/-1)
test/Makefile.am (+1/-0)
test/Makefile.in (+151/-58)
test/bench/Makefile.in (+76/-24)
test/etap/001-load.t (+2/-17)
test/etap/020-btree-basics.t (+2/-2)
test/etap/040-util.t (+2/-2)
test/etap/041-uuid-gen-id.ini (+20/-0)
test/etap/041-uuid-gen.t (+31/-2)
test/etap/050-stream.t (+4/-4)
test/etap/072-cleanup.t (+3/-3)
test/etap/073-changes.t (+1/-1)
test/etap/074-doc-update-conflicts.t (+218/-0)
test/etap/075-auth-cache.t (+3/-1)
test/etap/076-file-compression.t (+7/-6)
test/etap/077-couch-db-fast-db-delete-create.t (+61/-0)
test/etap/080-config-get-set.t (+1/-1)
test/etap/083-config-no-files.t (+0/-2)
test/etap/090-task-status.t (+0/-3)
test/etap/120-stats-collect.t (+7/-7)
test/etap/140-attachment-comp.t (+4/-1)
test/etap/160-vhosts.t (+12/-31)
test/etap/200-view-group-no-db-leaks.t (+21/-49)
test/etap/201-view-group-shutdown.t (+9/-19)
test/etap/220-compaction-daemon.t (+19/-21)
test/etap/230-httpc-pool.t (+0/-250)
test/etap/230-pbkfd2.t (+38/-0)
test/etap/231-cors.t (+449/-0)
test/etap/240-replication-compact.t (+0/-488)
test/etap/241-replication-large-atts.t (+0/-267)
test/etap/242-replication-many-leaves.t (+0/-294)
test/etap/243-doc-missing-stubs.t (+0/-304)
test/etap/250-upgrade-legacy-view-files.t (+168/-0)
test/etap/Makefile.am (+19/-9)
test/etap/Makefile.in (+130/-61)
test/etap/random_port.ini (+0/-19)
test/etap/run.tpl (+16/-11)
test/etap/test_util.erl.in (+25/-3)
test/javascript/Makefile.am (+2/-0)
test/javascript/Makefile.in (+78/-24)
test/javascript/cli_runner.js (+34/-39)
test/javascript/couch_http.js (+16/-5)
test/javascript/run.tpl (+91/-12)
test/javascript/test_setup.js (+89/-0)
test/random_port.ini (+19/-0)
test/view_server/Makefile.in (+76/-24)
utils/Makefile.am (+1/-1)
utils/Makefile.in (+77/-25)
var/Makefile.in (+76/-25)
To merge this branch: bzr merge lp:~jderose/ubuntu/saucy/couchdb/1.4.0
Reviewer Review Type Date Requested Status
Andrew Starr-Bochicchio (community) Approve
Chad Miller (community) Approve
Jason Gerard DeRose (community) Needs Resubmitting
Ubuntu branches Pending
Review via email: mp+182725@code.launchpad.net
To post a comment you must log in.
114. By Jason Gerard DeRose

merge-upstream 1.4.0 (no change from 1.4.0-rc.1)

Revision history for this message
Chad Miller (cmiller) wrote :

So nice. $ bzr diff -r72.. debian/

1)
+XSBC-Original-Maintainer: Jason Gerard DeRose <email address hidden>
This should be whoever owned the package in the previous packaging, which usually means the Debian maintainer, but can sometimes be the previous person in Ubuntu. It shouldn't be whoever's in the changelog.

2)
-case $1 in
- configure)
- if dpkg --compare-versions "$2" lt-nl 1.2.0-2ubuntu1; then
Should you be dropping this? Someone could go from 1.1 to 1.4.

3)
-get-orig-source:
- uscan --force-download --rename --download-version=$(DEB_UPSTREAM_VERSION) --destdir .
This rule can be useful. In fact, I'd update it so that it uses the most recent standard: Rule should be
"get-packaged-orig-source", and it inherits ORIG_PACKAGE and ORIG_VERSION as Make/environment variables, so it should download orig sources, clean them up, and make a tarball in the current dir that extracts correctly (tar xf ORIG_PACKAGE+"_"+ORIG_SOURCE+".orig.tar.gz" -> "./"+ORIG_PACKAGE+"-"+ORIG_VERSION). This assumes you know where the official tarball or sources will be at release.

review: Needs Fixing
115. By Jason Gerard DeRose

Fixed up changelog

116. By Jason Gerard DeRose

oops, revert XSBC-Original-Maintainer to Laszlo Boszormenyi (GCS) <email address hidden>

117. By Jason Gerard DeRose

oops, we still need couchdb-bin.postinst

118. By Jason Gerard DeRose

Updated debian/watch file to use current http://www.apache.org/dist/couchdb/source/ location

119. By Jason Gerard DeRose

Added a get-packaged-orig-source rule

120. By Jason Gerard DeRose

Updated changelog with a few last bits

Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Thanks, Chad!

So I've got those 3 things fixed, and I also fixed the debian/watch file, which wasn't pointing to the current download location.

I also got word from the CouchDB folks that the 1.4.0 release is now golden (no change from 1.4.0-rc.1), so I updated the version in the changelog to reflect this (note the 1.4.0 release announcement hasn't been made yet).

review: Needs Resubmitting
Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Oh, one more thing, something about UDD or quilt caused two conflicts when you try to merge this into lp:ubuntu/saucy/couchdb:

conflicts:
  Text conflict in bin/couchdb.tpl.in
  Text conflict in etc/init/couchdb.tpl.in

They can be correctly resolved with:

bzr resolve --all --take-other

Revision history for this message
Chad Miller (cmiller) wrote :

Okay. In the future, Jason, I think the quilt state directory '.pc' should be added to bzr's ignores list. Not important now.

review: Approve
Revision history for this message
Chad Miller (cmiller) wrote :

Jason, another wishlist thing to add in the future is "autopkgtests", so we can detect breakage between couchdb--erlang, and maybe novacut--c--e one day.

Revision history for this message
Chad Miller (cmiller) wrote :

Jason, also pay attention to lintian messages. Fix these "E" at least for next upload. Maybe you can ignore the init.d ones, assuming you Depend on upstart.

W: couchdb-common: debian-changelog-line-too-long line 14
W: couchdb-common: embedded-javascript-library usr/share/couchdb/www/docs/_static/jquery.js
W: couchdb-common: embedded-javascript-library usr/share/couchdb/www/docs/_static/underscore.js
W: couchdb-common: embedded-javascript-library usr/share/couchdb/www/script/jquery.form.js
W: couchdb-common: embedded-javascript-library usr/share/couchdb/www/script/jquery.js
W: couchdb-common: executable-not-elf-or-script usr/share/couchdb/server/main.js
W: couchdb-common: executable-not-elf-or-script usr/share/couchdb/server/main-coffee.js
W: couchdb-bin: debian-changelog-line-too-long line 14
W: couchdb-bin: virtual-package-depends-without-real-package-depends depends: erlang-abi-15.b
E: couchdb-bin: package-contains-info-dir-file usr/share/info/dir.gz
W: couchdb-bin: binary-without-manpage usr/bin/couch-config
E: couchdb-bin: non-empty-dependency_libs-in-la-file usr/lib/i386-linux-gnu/couchdb/erlang/lib/couch-1.4.0/priv/lib/couch_ejson_compare.la
E: couchdb-bin: non-empty-dependency_libs-in-la-file usr/lib/i386-linux-gnu/couchdb/erlang/lib/couch-1.4.0/priv/lib/couch_icu_driver.la
E: couchdb-bin: non-empty-dependency_libs-in-la-file usr/lib/i386-linux-gnu/couchdb/erlang/lib/ejson-0.1.0/priv/ejson.la
E: couchdb-bin: non-empty-dependency_libs-in-la-file usr/lib/i386-linux-gnu/couchdb/erlang/lib/snappy-1.0.5/priv/snappy_nif.la
W: couchdb: debian-changelog-line-too-long line 14
E: couchdb: postrm-does-not-call-updaterc.d-for-init.d-script etc/init.d/couchdb
W: couchdb: init.d-script-not-marked-as-conffile etc/init.d/couchdb
E: couchdb: init.d-script-not-included-in-package etc/init.d/couchdb

121. By Jason Gerard DeRose

Fix linian non-empty-dependency_libs-in-la-file warnings

122. By Jason Gerard DeRose

Fix lintian debian-changelog-line-too-long warning

123. By Jason Gerard DeRose

Oops, didn't mean to commit with --disable-tests

Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Chad,

So you don't need to keep .pc under version control for UDD any more?

Yeah, I'm keen adding some autopkgtests goodness. It would be good to test couchdb as a reverse dependency whenever erlang is updated, and testing the novacut components as a reverse dependency whenever couchdb is updated would also be awesome. Although these days couchdb has quite extensive unit tests that get run during the builds, so at least we're not completely lacking it automatic test coverage in the present. Could be much better though.

So I fixed the non-empty-dependency_libs-in-la-file lintian errors, and also fixed the debian-changelog-line-too-long warning.

Out of curiosity, how are you running lintian? When I run it, I'm not seeing the package-contains-info-dir-file error, for some reason.

Thanks again for all your help!

Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Oh, and the last two lintian errors seem to be spurious, just the result of lintian not groking upstart:
https://bugs.launchpad.net/ubuntu/+source/lintian/+bug/1030195

Revision history for this message
Chad Miller (cmiller) wrote :

Jason, quilt state files in .pc/ should never be in Bazaar version control. Only the results of using quilt, a set of patch files in debian/, should be in Bazaar version control.

I'm running lintian as the automatic step at the end of "bzr builddeb", on Saucy.

Revision history for this message
Andrew Starr-Bochicchio (andrewsomething) :
review: Approve
Revision history for this message
Robie Basak (racb) wrote :

This is uploaded now, so closing out this MP.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file '.pc/applied-patches'
--- .pc/applied-patches 2013-01-18 22:04:32 +0000
+++ .pc/applied-patches 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1force-reload.patch
2couchdb_own_rundir.patch
3logrotate_as_couchdb.patch
4couchdb_sighup.patch
5wait_for_couchdb_stop.patch
6improve_parsing_of_mochiweb_relative_paths.patch
7improve_script_url_validation.patch
8include_a_comment_before_jsonp_output.patch
90
=== removed directory '.pc/couchdb_own_rundir.patch'
=== removed directory '.pc/couchdb_own_rundir.patch/etc'
=== removed directory '.pc/couchdb_own_rundir.patch/etc/init'
=== removed file '.pc/couchdb_own_rundir.patch/etc/init/couchdb.tpl.in'
--- .pc/couchdb_own_rundir.patch/etc/init/couchdb.tpl.in 2012-07-19 20:13:25 +0000
+++ .pc/couchdb_own_rundir.patch/etc/init/couchdb.tpl.in 1970-01-01 00:00:00 +0000
@@ -1,156 +0,0 @@
1#!/bin/sh -e
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15### BEGIN INIT INFO
16# Provides: couchdb
17# Required-Start: $local_fs $remote_fs
18# Required-Stop: $local_fs $remote_fs
19# Default-Start: 2 3 4 5
20# Default-Stop: 0 1 6
21# Short-Description: Apache CouchDB init script
22# Description: Apache CouchDB init script for the database server.
23### END INIT INFO
24
25SCRIPT_OK=0
26SCRIPT_ERROR=1
27
28DESCRIPTION="database server"
29NAME=couchdb
30SCRIPT_NAME=`basename $0`
31COUCHDB=%bindir%/%couchdb_command_name%
32CONFIGURATION_FILE=%sysconfdir%/default/couchdb
33RUN_DIR=%localstaterundir%
34LSB_LIBRARY=/lib/lsb/init-functions
35
36if test ! -x $COUCHDB; then
37 exit $SCRIPT_ERROR
38fi
39
40if test -r $CONFIGURATION_FILE; then
41 . $CONFIGURATION_FILE
42fi
43
44log_daemon_msg () {
45 # Dummy function to be replaced by LSB library.
46
47 echo $@
48}
49
50log_end_msg () {
51 # Dummy function to be replaced by LSB library.
52
53 if test "$1" != "0"; then
54 echo "Error with $DESCRIPTION: $NAME"
55 fi
56 return $1
57}
58
59if test -r $LSB_LIBRARY; then
60 . $LSB_LIBRARY
61fi
62
63run_command () {
64 command="$1"
65 if test -n "$COUCHDB_OPTIONS"; then
66 command="$command $COUCHDB_OPTIONS"
67 fi
68 if test -n "$COUCHDB_USER"; then
69 if su $COUCHDB_USER -c "$command"; then
70 return $SCRIPT_OK
71 else
72 return $SCRIPT_ERROR
73 fi
74 else
75 if $command; then
76 return $SCRIPT_OK
77 else
78 return $SCRIPT_ERROR
79 fi
80 fi
81}
82
83start_couchdb () {
84 # Start Apache CouchDB as a background process.
85
86 mkdir -p "$RUN_DIR"
87 command="$COUCHDB -b"
88 if test -n "$COUCHDB_STDOUT_FILE"; then
89 command="$command -o $COUCHDB_STDOUT_FILE"
90 fi
91 if test -n "$COUCHDB_STDERR_FILE"; then
92 command="$command -e $COUCHDB_STDERR_FILE"
93 fi
94 if test -n "$COUCHDB_RESPAWN_TIMEOUT"; then
95 command="$command -r $COUCHDB_RESPAWN_TIMEOUT"
96 fi
97 run_command "$command" > /dev/null
98}
99
100stop_couchdb () {
101 # Stop the running Apache CouchDB process.
102
103 run_command "$COUCHDB -d" > /dev/null
104}
105
106display_status () {
107 # Display the status of the running Apache CouchDB process.
108
109 run_command "$COUCHDB -s"
110}
111
112parse_script_option_list () {
113 # Parse arguments passed to the script and take appropriate action.
114
115 case "$1" in
116 start)
117 log_daemon_msg "Starting $DESCRIPTION" $NAME
118 if start_couchdb; then
119 log_end_msg $SCRIPT_OK
120 else
121 log_end_msg $SCRIPT_ERROR
122 fi
123 ;;
124 stop)
125 log_daemon_msg "Stopping $DESCRIPTION" $NAME
126 if stop_couchdb; then
127 log_end_msg $SCRIPT_OK
128 else
129 log_end_msg $SCRIPT_ERROR
130 fi
131 ;;
132 restart|force-reload)
133 log_daemon_msg "Restarting $DESCRIPTION" $NAME
134 if stop_couchdb; then
135 if start_couchdb; then
136 log_end_msg $SCRIPT_OK
137 else
138 log_end_msg $SCRIPT_ERROR
139 fi
140 else
141 log_end_msg $SCRIPT_ERROR
142 fi
143 ;;
144 status)
145 display_status
146 ;;
147 *)
148 cat << EOF >&2
149Usage: $SCRIPT_NAME {start|stop|restart|force-reload|status}
150EOF
151 exit $SCRIPT_ERROR
152 ;;
153 esac
154}
155
156parse_script_option_list $@
1570
=== removed directory '.pc/couchdb_sighup.patch'
=== removed directory '.pc/couchdb_sighup.patch/bin'
=== removed file '.pc/couchdb_sighup.patch/bin/couchdb.tpl.in'
--- .pc/couchdb_sighup.patch/bin/couchdb.tpl.in 2012-11-18 12:24:24 +0000
+++ .pc/couchdb_sighup.patch/bin/couchdb.tpl.in 1970-01-01 00:00:00 +0000
@@ -1,335 +0,0 @@
1#! /bin/sh -e
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15BACKGROUND=false
16DEFAULT_CONFIG_DIR=%localconfdir%/default.d
17DEFAULT_CONFIG_FILE=%localconfdir%/%defaultini%
18ERL_OS_MON_OPTIONS="-os_mon \
19 start_memsup false \
20 start_cpu_sup false \
21 disk_space_check_interval 1 \
22 disk_almost_full_threshold 1"
23ERL_START_OPTIONS="$ERL_OS_MON_OPTIONS -sasl errlog_type error +K true +A 4"
24HEART_BEAT_TIMEOUT=11
25HEART_COMMAND="%bindir%/%couchdb_command_name% -k"
26INTERACTIVE=false
27KILL=false
28LOCAL_CONFIG_DIR=%localconfdir%/local.d
29LOCAL_CONFIG_FILE=%localconfdir%/%localini%
30PID_FILE=%localstatedir%/run/couchdb/couchdb.pid
31RECURSED=false
32RESET_CONFIG=true
33RESPAWN_TIMEOUT=0
34SCRIPT_ERROR=1
35SCRIPT_OK=0
36SHUTDOWN=false
37STDERR_FILE=couchdb.stderr
38STDOUT_FILE=couchdb.stdout
39
40print_arguments=""
41start_arguments=""
42background_start_arguments=""
43
44basename=`basename $0`
45
46display_version () {
47 cat << EOF
48$basename - %package_name% %version%
49
50Licensed under the Apache License, Version 2.0 (the "License"); you may not use
51this file except in compliance with the License. You may obtain a copy of the
52License at
53
54 http://www.apache.org/licenses/LICENSE-2.0
55
56Unless required by applicable law or agreed to in writing, software distributed
57under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
58CONDITIONS OF ANY KIND, either express or implied. See the License for the
59specific language governing permissions and limitations under the License.
60
61EOF
62}
63
64display_help () {
65 cat << EOF
66Usage: $basename [OPTION]
67
68The $basename command runs the %package_name% server.
69
70Erlang is called with:
71
72 $ERL_START_OPTIONS
73
74Erlang inherits the environment of this command.
75
76You can override these options using the environment:
77
78 ERL_AFLAGS, ERL_FLAGS, ERL_ZFLAGS
79
80See erl(1) for more information about the environment variables.
81
82The exit status is 0 for success or 1 for failure.
83
84Options:
85
86 -h display a short help message and exit
87 -V display version information and exit
88 -a FILE add configuration FILE to chain
89 -A DIR add configuration DIR to chain
90 -n reset configuration file chain (including system default)
91 -c print configuration file chain and exit
92 -i use the interactive Erlang shell
93 -b spawn as a background process
94 -p FILE set the background PID FILE (overrides system default)
95 -r SECONDS respawn background process after SECONDS (defaults to no respawn)
96 -o FILE redirect background stdout to FILE (defaults to $STDOUT_FILE)
97 -e FILE redirect background stderr to FILE (defaults to $STDERR_FILE)
98 -s display the status of the background process
99 -k kill the background process, will respawn if needed
100 -d shutdown the background process
101
102Report bugs at <%bug_uri%>.
103EOF
104}
105
106display_error () {
107 if test -n "$1"; then
108 echo $1 >&2
109 fi
110 echo >&2
111 echo "Try \`"$basename" -h' for more information." >&2
112 false
113}
114
115_get_pid () {
116 if test -f $PID_FILE; then
117 PID=`cat $PID_FILE`
118 fi
119 echo $PID
120}
121
122_add_config_file () {
123 if test -z "$print_arguments"; then
124 print_arguments="$1"
125 else
126 print_arguments="`cat <<EOF
127$print_arguments
128$1
129EOF
130`"
131 fi
132 start_arguments="$start_arguments $1"
133 background_start_arguments="$background_start_arguments -a $1"
134}
135
136_add_config_dir () {
137 for file in "$1"/*.ini; do
138 if [ -r "$file" ]; then
139 _add_config_file "$file"
140 fi
141 done
142}
143
144_load_config () {
145 _add_config_file "$DEFAULT_CONFIG_FILE"
146 _add_config_dir "$DEFAULT_CONFIG_DIR"
147 _add_config_file "$LOCAL_CONFIG_FILE"
148 _add_config_dir "$LOCAL_CONFIG_DIR"
149}
150
151_reset_config () {
152 print_arguments=""
153 start_arguments=""
154 background_start_arguments="-n"
155}
156
157_print_config () {
158 cat <<EOF
159$print_arguments
160EOF
161}
162
163check_status () {
164 PID=`_get_pid`
165 if test -n "$PID"; then
166 if kill -0 $PID 2> /dev/null; then
167 echo "Apache CouchDB is running as process $PID, time to relax."
168 return $SCRIPT_OK
169 else
170 echo >&2 << EOF
171Apache CouchDB is not running but a stale PID file exists: $PID_FILE
172EOF
173 fi
174 else
175 echo "Apache CouchDB is not running." >&2
176 fi
177 return $SCRIPT_ERROR
178}
179
180check_environment () {
181 if test "$BACKGROUND" != "true"; then
182 return
183 fi
184 touch $PID_FILE 2> /dev/null || true
185 touch $STDOUT_FILE 2> /dev/null || true
186 touch $STDERR_FILE 2> /dev/null || true
187 message_prefix="Apache CouchDB needs write permission on the"
188 if test ! -w $PID_FILE; then
189 echo "$message_prefix PID file: $PID_FILE" >&2
190 false
191 fi
192 if test ! -w $STDOUT_FILE; then
193 echo "$message_prefix STDOUT file: $STDOUT_FILE" >&2
194 false
195 fi
196 if test ! -w $STDERR_FILE; then
197 echo "$message_prefix STDERR file: $STDERR_FILE" >&2
198 false
199 fi
200 message_prefix="Apache CouchDB needs a regular"
201 if test `echo 2> /dev/null >> $PID_FILE; echo $?` -gt 0; then
202 echo "$message_prefix PID file: $PID_FILE" >&2
203 false
204 fi
205 if test `echo 2> /dev/null >> $STDOUT_FILE; echo $?` -gt 0; then
206 echo "$message_prefix STDOUT file: $STDOUT_FILE" >&2
207 false
208 fi
209 if test `echo 2> /dev/null >> $STDERR_FILE; echo $?` -gt 0; then
210 echo "$message_prefix STDERR file: $STDERR_FILE" >&2
211 false
212 fi
213}
214
215start_couchdb () {
216 if test ! "$RECURSED" = "true"; then
217 if check_status 2> /dev/null; then
218 exit
219 fi
220 check_environment
221 fi
222 interactive_option="+Bd -noinput"
223 if test "$INTERACTIVE" = "true"; then
224 interactive_option=""
225 fi
226 if test "$BACKGROUND" = "true"; then
227 touch $PID_FILE
228 interactive_option="+Bd -noinput"
229 fi
230 command="%ERL% $interactive_option $ERL_START_OPTIONS \
231 -env ERL_LIBS %localerlanglibdir% -couch_ini $start_arguments -s couch"
232 if test "$BACKGROUND" = "true" -a "$RECURSED" = "false"; then
233 $0 $background_start_arguments -b -r $RESPAWN_TIMEOUT -p $PID_FILE \
234 -o $STDOUT_FILE -e $STDERR_FILE -R &
235 echo "Apache CouchDB has started, time to relax."
236 else
237 if test "$RECURSED" = "true"; then
238 while true; do
239 export HEART_COMMAND
240 export HEART_BEAT_TIMEOUT
241 `eval $command -pidfile $PID_FILE -heart \
242 >> $STDOUT_FILE 2>> $STDERR_FILE` || true
243 PID=`_get_pid`
244 if test -n "$PID"; then
245 if kill -0 $PID 2> /dev/null; then
246 return $SCRIPT_ERROR
247 fi
248 else
249 return $SCRIPT_OK
250 fi
251 if test "$RESPAWN_TIMEOUT" = "0"; then
252 return $SCRIPT_OK
253 fi
254 if test "$RESPAWN_TIMEOUT" != "1"; then
255 plural_ending="s"
256 fi
257 cat << EOF
258Apache CouchDB crashed, restarting in $RESPAWN_TIMEOUT second$plural_ending.
259EOF
260 sleep $RESPAWN_TIMEOUT
261 done
262 else
263 eval exec $command
264 fi
265 fi
266}
267
268stop_couchdb () {
269 PID=`_get_pid`
270 if test -n "$PID"; then
271 if test "$1" = "false"; then
272 echo > $PID_FILE
273 fi
274 if kill -0 $PID 2> /dev/null; then
275 if kill -1 $PID 2> /dev/null; then
276 if test "$1" = "false"; then
277 echo "Apache CouchDB has been shutdown."
278 else
279 echo "Apache CouchDB has been killed."
280 fi
281 return $SCRIPT_OK
282 else
283 echo "Apache CouchDB could not be killed." >&2
284 return $SCRIPT_ERROR
285 fi
286 if test "$1" = "false"; then
287 echo "Stale PID file exists but Apache CouchDB is not running."
288 else
289 echo "Stale PID file existed but Apache CouchDB is not running."
290 fi
291 fi
292 else
293 echo "Apache CouchDB is not running."
294 fi
295}
296
297parse_script_option_list () {
298 _load_config
299 set +e
300 options=`getopt hVa:A:ncibp:r:Ro:e:skd $@`
301 if test ! $? -eq 0; then
302 display_error
303 fi
304 set -e
305 eval set -- $options
306 while [ $# -gt 0 ]; do
307 case "$1" in
308 -h) shift; display_help; exit;;
309 -V) shift; display_version; exit;;
310 -a) shift; _add_config_file "$1"; shift;;
311 -A) shift; _add_config_dir "$1"; shift;;
312 -n) shift; _reset_config;;
313 -c) shift; _print_config; exit;;
314 -i) shift; INTERACTIVE=true;;
315 -b) shift; BACKGROUND=true;;
316 -r) shift; RESPAWN_TIMEOUT=$1; shift;;
317 -R) shift; RECURSED=true;;
318 -p) shift; PID_FILE=$1; shift;;
319 -o) shift; STDOUT_FILE=$1; shift;;
320 -e) shift; STDERR_FILE=$1; shift;;
321 -s) shift; check_status; exit;;
322 -k) shift; KILL=true;;
323 -d) shift; SHUTDOWN=true;;
324 --) shift; break;;
325 *) display_error "Unknown option: $1" >&2;;
326 esac
327 done
328 if test "$KILL" = "true" -o "$SHUTDOWN" = "true"; then
329 stop_couchdb $KILL
330 else
331 start_couchdb
332 fi
333}
334
335parse_script_option_list $@
3360
=== removed directory '.pc/force-reload.patch'
=== removed directory '.pc/force-reload.patch/etc'
=== removed directory '.pc/force-reload.patch/etc/init'
=== removed file '.pc/force-reload.patch/etc/init/couchdb.tpl.in'
--- .pc/force-reload.patch/etc/init/couchdb.tpl.in 2012-04-10 21:14:05 +0000
+++ .pc/force-reload.patch/etc/init/couchdb.tpl.in 1970-01-01 00:00:00 +0000
@@ -1,156 +0,0 @@
1#!/bin/sh -e
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15### BEGIN INIT INFO
16# Provides: couchdb
17# Required-Start: $local_fs $remote_fs
18# Required-Stop: $local_fs $remote_fs
19# Default-Start: 2 3 4 5
20# Default-Stop: 0 1 6
21# Short-Description: Apache CouchDB init script
22# Description: Apache CouchDB init script for the database server.
23### END INIT INFO
24
25SCRIPT_OK=0
26SCRIPT_ERROR=1
27
28DESCRIPTION="database server"
29NAME=couchdb
30SCRIPT_NAME=`basename $0`
31COUCHDB=%bindir%/%couchdb_command_name%
32CONFIGURATION_FILE=%sysconfdir%/default/couchdb
33RUN_DIR=%localstaterundir%
34LSB_LIBRARY=/lib/lsb/init-functions
35
36if test ! -x $COUCHDB; then
37 exit $SCRIPT_ERROR
38fi
39
40if test -r $CONFIGURATION_FILE; then
41 . $CONFIGURATION_FILE
42fi
43
44log_daemon_msg () {
45 # Dummy function to be replaced by LSB library.
46
47 echo $@
48}
49
50log_end_msg () {
51 # Dummy function to be replaced by LSB library.
52
53 if test "$1" != "0"; then
54 echo "Error with $DESCRIPTION: $NAME"
55 fi
56 return $1
57}
58
59if test -r $LSB_LIBRARY; then
60 . $LSB_LIBRARY
61fi
62
63run_command () {
64 command="$1"
65 if test -n "$COUCHDB_OPTIONS"; then
66 command="$command $COUCHDB_OPTIONS"
67 fi
68 if test -n "$COUCHDB_USER"; then
69 if su $COUCHDB_USER -c "$command"; then
70 return $SCRIPT_OK
71 else
72 return $SCRIPT_ERROR
73 fi
74 else
75 if $command; then
76 return $SCRIPT_OK
77 else
78 return $SCRIPT_ERROR
79 fi
80 fi
81}
82
83start_couchdb () {
84 # Start Apache CouchDB as a background process.
85
86 mkdir -p "$RUN_DIR"
87 command="$COUCHDB -b"
88 if test -n "$COUCHDB_STDOUT_FILE"; then
89 command="$command -o $COUCHDB_STDOUT_FILE"
90 fi
91 if test -n "$COUCHDB_STDERR_FILE"; then
92 command="$command -e $COUCHDB_STDERR_FILE"
93 fi
94 if test -n "$COUCHDB_RESPAWN_TIMEOUT"; then
95 command="$command -r $COUCHDB_RESPAWN_TIMEOUT"
96 fi
97 run_command "$command" > /dev/null
98}
99
100stop_couchdb () {
101 # Stop the running Apache CouchDB process.
102
103 run_command "$COUCHDB -d" > /dev/null
104}
105
106display_status () {
107 # Display the status of the running Apache CouchDB process.
108
109 run_command "$COUCHDB -s"
110}
111
112parse_script_option_list () {
113 # Parse arguments passed to the script and take appropriate action.
114
115 case "$1" in
116 start)
117 log_daemon_msg "Starting $DESCRIPTION" $NAME
118 if start_couchdb; then
119 log_end_msg $SCRIPT_OK
120 else
121 log_end_msg $SCRIPT_ERROR
122 fi
123 ;;
124 stop)
125 log_daemon_msg "Stopping $DESCRIPTION" $NAME
126 if stop_couchdb; then
127 log_end_msg $SCRIPT_OK
128 else
129 log_end_msg $SCRIPT_ERROR
130 fi
131 ;;
132 restart)
133 log_daemon_msg "Restarting $DESCRIPTION" $NAME
134 if stop_couchdb; then
135 if start_couchdb; then
136 log_end_msg $SCRIPT_OK
137 else
138 log_end_msg $SCRIPT_ERROR
139 fi
140 else
141 log_end_msg $SCRIPT_ERROR
142 fi
143 ;;
144 status)
145 display_status
146 ;;
147 *)
148 cat << EOF >&2
149Usage: $SCRIPT_NAME {start|stop|restart|status}
150EOF
151 exit $SCRIPT_ERROR
152 ;;
153 esac
154}
155
156parse_script_option_list $@
1570
=== removed directory '.pc/improve_parsing_of_mochiweb_relative_paths.patch'
=== removed directory '.pc/improve_parsing_of_mochiweb_relative_paths.patch/src'
=== removed directory '.pc/improve_parsing_of_mochiweb_relative_paths.patch/src/mochiweb'
=== removed file '.pc/improve_parsing_of_mochiweb_relative_paths.patch/src/mochiweb/mochiweb_util.erl'
--- .pc/improve_parsing_of_mochiweb_relative_paths.patch/src/mochiweb/mochiweb_util.erl 2013-01-18 22:04:32 +0000
+++ .pc/improve_parsing_of_mochiweb_relative_paths.patch/src/mochiweb/mochiweb_util.erl 1970-01-01 00:00:00 +0000
@@ -1,973 +0,0 @@
1%% @author Bob Ippolito <bob@mochimedia.com>
2%% @copyright 2007 Mochi Media, Inc.
3
4%% @doc Utilities for parsing and quoting.
5
6-module(mochiweb_util).
7-author('bob@mochimedia.com').
8-export([join/2, quote_plus/1, urlencode/1, parse_qs/1, unquote/1]).
9-export([path_split/1]).
10-export([urlsplit/1, urlsplit_path/1, urlunsplit/1, urlunsplit_path/1]).
11-export([guess_mime/1, parse_header/1]).
12-export([shell_quote/1, cmd/1, cmd_string/1, cmd_port/2, cmd_status/1]).
13-export([record_to_proplist/2, record_to_proplist/3]).
14-export([safe_relative_path/1, partition/2]).
15-export([parse_qvalues/1, pick_accepted_encodings/3]).
16-export([make_io/1]).
17
18-define(PERCENT, 37). % $\%
19-define(FULLSTOP, 46). % $\.
20-define(IS_HEX(C), ((C >= $0 andalso C =< $9) orelse
21 (C >= $a andalso C =< $f) orelse
22 (C >= $A andalso C =< $F))).
23-define(QS_SAFE(C), ((C >= $a andalso C =< $z) orelse
24 (C >= $A andalso C =< $Z) orelse
25 (C >= $0 andalso C =< $9) orelse
26 (C =:= ?FULLSTOP orelse C =:= $- orelse C =:= $~ orelse
27 C =:= $_))).
28
29hexdigit(C) when C < 10 -> $0 + C;
30hexdigit(C) when C < 16 -> $A + (C - 10).
31
32unhexdigit(C) when C >= $0, C =< $9 -> C - $0;
33unhexdigit(C) when C >= $a, C =< $f -> C - $a + 10;
34unhexdigit(C) when C >= $A, C =< $F -> C - $A + 10.
35
36%% @spec partition(String, Sep) -> {String, [], []} | {Prefix, Sep, Postfix}
37%% @doc Inspired by Python 2.5's str.partition:
38%% partition("foo/bar", "/") = {"foo", "/", "bar"},
39%% partition("foo", "/") = {"foo", "", ""}.
40partition(String, Sep) ->
41 case partition(String, Sep, []) of
42 undefined ->
43 {String, "", ""};
44 Result ->
45 Result
46 end.
47
48partition("", _Sep, _Acc) ->
49 undefined;
50partition(S, Sep, Acc) ->
51 case partition2(S, Sep) of
52 undefined ->
53 [C | Rest] = S,
54 partition(Rest, Sep, [C | Acc]);
55 Rest ->
56 {lists:reverse(Acc), Sep, Rest}
57 end.
58
59partition2(Rest, "") ->
60 Rest;
61partition2([C | R1], [C | R2]) ->
62 partition2(R1, R2);
63partition2(_S, _Sep) ->
64 undefined.
65
66
67
68%% @spec safe_relative_path(string()) -> string() | undefined
69%% @doc Return the reduced version of a relative path or undefined if it
70%% is not safe. safe relative paths can be joined with an absolute path
71%% and will result in a subdirectory of the absolute path.
72safe_relative_path("/" ++ _) ->
73 undefined;
74safe_relative_path(P) ->
75 safe_relative_path(P, []).
76
77safe_relative_path("", Acc) ->
78 case Acc of
79 [] ->
80 "";
81 _ ->
82 string:join(lists:reverse(Acc), "/")
83 end;
84safe_relative_path(P, Acc) ->
85 case partition(P, "/") of
86 {"", "/", _} ->
87 %% /foo or foo//bar
88 undefined;
89 {"..", _, _} when Acc =:= [] ->
90 undefined;
91 {"..", _, Rest} ->
92 safe_relative_path(Rest, tl(Acc));
93 {Part, "/", ""} ->
94 safe_relative_path("", ["", Part | Acc]);
95 {Part, _, Rest} ->
96 safe_relative_path(Rest, [Part | Acc])
97 end.
98
99%% @spec shell_quote(string()) -> string()
100%% @doc Quote a string according to UNIX shell quoting rules, returns a string
101%% surrounded by double quotes.
102shell_quote(L) ->
103 shell_quote(L, [$\"]).
104
105%% @spec cmd_port([string()], Options) -> port()
106%% @doc open_port({spawn, mochiweb_util:cmd_string(Argv)}, Options).
107cmd_port(Argv, Options) ->
108 open_port({spawn, cmd_string(Argv)}, Options).
109
110%% @spec cmd([string()]) -> string()
111%% @doc os:cmd(cmd_string(Argv)).
112cmd(Argv) ->
113 os:cmd(cmd_string(Argv)).
114
115%% @spec cmd_string([string()]) -> string()
116%% @doc Create a shell quoted command string from a list of arguments.
117cmd_string(Argv) ->
118 string:join([shell_quote(X) || X <- Argv], " ").
119
120%% @spec cmd_status([string()]) -> {ExitStatus::integer(), Stdout::binary()}
121%% @doc Accumulate the output and exit status from the given application, will be
122%% spawned with cmd_port/2.
123cmd_status(Argv) ->
124 Port = cmd_port(Argv, [exit_status, stderr_to_stdout,
125 use_stdio, binary]),
126 try cmd_loop(Port, [])
127 after catch port_close(Port)
128 end.
129
130%% @spec cmd_loop(port(), list()) -> {ExitStatus::integer(), Stdout::binary()}
131%% @doc Accumulate the output and exit status from a port.
132cmd_loop(Port, Acc) ->
133 receive
134 {Port, {exit_status, Status}} ->
135 {Status, iolist_to_binary(lists:reverse(Acc))};
136 {Port, {data, Data}} ->
137 cmd_loop(Port, [Data | Acc])
138 end.
139
140%% @spec join([iolist()], iolist()) -> iolist()
141%% @doc Join a list of strings or binaries together with the given separator
142%% string or char or binary. The output is flattened, but may be an
143%% iolist() instead of a string() if any of the inputs are binary().
144join([], _Separator) ->
145 [];
146join([S], _Separator) ->
147 lists:flatten(S);
148join(Strings, Separator) ->
149 lists:flatten(revjoin(lists:reverse(Strings), Separator, [])).
150
151revjoin([], _Separator, Acc) ->
152 Acc;
153revjoin([S | Rest], Separator, []) ->
154 revjoin(Rest, Separator, [S]);
155revjoin([S | Rest], Separator, Acc) ->
156 revjoin(Rest, Separator, [S, Separator | Acc]).
157
158%% @spec quote_plus(atom() | integer() | float() | string() | binary()) -> string()
159%% @doc URL safe encoding of the given term.
160quote_plus(Atom) when is_atom(Atom) ->
161 quote_plus(atom_to_list(Atom));
162quote_plus(Int) when is_integer(Int) ->
163 quote_plus(integer_to_list(Int));
164quote_plus(Binary) when is_binary(Binary) ->
165 quote_plus(binary_to_list(Binary));
166quote_plus(Float) when is_float(Float) ->
167 quote_plus(mochinum:digits(Float));
168quote_plus(String) ->
169 quote_plus(String, []).
170
171quote_plus([], Acc) ->
172 lists:reverse(Acc);
173quote_plus([C | Rest], Acc) when ?QS_SAFE(C) ->
174 quote_plus(Rest, [C | Acc]);
175quote_plus([$\s | Rest], Acc) ->
176 quote_plus(Rest, [$+ | Acc]);
177quote_plus([C | Rest], Acc) ->
178 <<Hi:4, Lo:4>> = <<C>>,
179 quote_plus(Rest, [hexdigit(Lo), hexdigit(Hi), ?PERCENT | Acc]).
180
181%% @spec urlencode([{Key, Value}]) -> string()
182%% @doc URL encode the property list.
183urlencode(Props) ->
184 Pairs = lists:foldr(
185 fun ({K, V}, Acc) ->
186 [quote_plus(K) ++ "=" ++ quote_plus(V) | Acc]
187 end, [], Props),
188 string:join(Pairs, "&").
189
190%% @spec parse_qs(string() | binary()) -> [{Key, Value}]
191%% @doc Parse a query string or application/x-www-form-urlencoded.
192parse_qs(Binary) when is_binary(Binary) ->
193 parse_qs(binary_to_list(Binary));
194parse_qs(String) ->
195 parse_qs(String, []).
196
197parse_qs([], Acc) ->
198 lists:reverse(Acc);
199parse_qs(String, Acc) ->
200 {Key, Rest} = parse_qs_key(String),
201 {Value, Rest1} = parse_qs_value(Rest),
202 parse_qs(Rest1, [{Key, Value} | Acc]).
203
204parse_qs_key(String) ->
205 parse_qs_key(String, []).
206
207parse_qs_key([], Acc) ->
208 {qs_revdecode(Acc), ""};
209parse_qs_key([$= | Rest], Acc) ->
210 {qs_revdecode(Acc), Rest};
211parse_qs_key(Rest=[$; | _], Acc) ->
212 {qs_revdecode(Acc), Rest};
213parse_qs_key(Rest=[$& | _], Acc) ->
214 {qs_revdecode(Acc), Rest};
215parse_qs_key([C | Rest], Acc) ->
216 parse_qs_key(Rest, [C | Acc]).
217
218parse_qs_value(String) ->
219 parse_qs_value(String, []).
220
221parse_qs_value([], Acc) ->
222 {qs_revdecode(Acc), ""};
223parse_qs_value([$; | Rest], Acc) ->
224 {qs_revdecode(Acc), Rest};
225parse_qs_value([$& | Rest], Acc) ->
226 {qs_revdecode(Acc), Rest};
227parse_qs_value([C | Rest], Acc) ->
228 parse_qs_value(Rest, [C | Acc]).
229
230%% @spec unquote(string() | binary()) -> string()
231%% @doc Unquote a URL encoded string.
232unquote(Binary) when is_binary(Binary) ->
233 unquote(binary_to_list(Binary));
234unquote(String) ->
235 qs_revdecode(lists:reverse(String)).
236
237qs_revdecode(S) ->
238 qs_revdecode(S, []).
239
240qs_revdecode([], Acc) ->
241 Acc;
242qs_revdecode([$+ | Rest], Acc) ->
243 qs_revdecode(Rest, [$\s | Acc]);
244qs_revdecode([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
245 qs_revdecode(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
246qs_revdecode([C | Rest], Acc) ->
247 qs_revdecode(Rest, [C | Acc]).
248
249%% @spec urlsplit(Url) -> {Scheme, Netloc, Path, Query, Fragment}
250%% @doc Return a 5-tuple, does not expand % escapes. Only supports HTTP style
251%% URLs.
252urlsplit(Url) ->
253 {Scheme, Url1} = urlsplit_scheme(Url),
254 {Netloc, Url2} = urlsplit_netloc(Url1),
255 {Path, Query, Fragment} = urlsplit_path(Url2),
256 {Scheme, Netloc, Path, Query, Fragment}.
257
258urlsplit_scheme(Url) ->
259 case urlsplit_scheme(Url, []) of
260 no_scheme ->
261 {"", Url};
262 Res ->
263 Res
264 end.
265
266urlsplit_scheme([C | Rest], Acc) when ((C >= $a andalso C =< $z) orelse
267 (C >= $A andalso C =< $Z) orelse
268 (C >= $0 andalso C =< $9) orelse
269 C =:= $+ orelse C =:= $- orelse
270 C =:= $.) ->
271 urlsplit_scheme(Rest, [C | Acc]);
272urlsplit_scheme([$: | Rest], Acc=[_ | _]) ->
273 {string:to_lower(lists:reverse(Acc)), Rest};
274urlsplit_scheme(_Rest, _Acc) ->
275 no_scheme.
276
277urlsplit_netloc("//" ++ Rest) ->
278 urlsplit_netloc(Rest, []);
279urlsplit_netloc(Path) ->
280 {"", Path}.
281
282urlsplit_netloc("", Acc) ->
283 {lists:reverse(Acc), ""};
284urlsplit_netloc(Rest=[C | _], Acc) when C =:= $/; C =:= $?; C =:= $# ->
285 {lists:reverse(Acc), Rest};
286urlsplit_netloc([C | Rest], Acc) ->
287 urlsplit_netloc(Rest, [C | Acc]).
288
289
290%% @spec path_split(string()) -> {Part, Rest}
291%% @doc Split a path starting from the left, as in URL traversal.
292%% path_split("foo/bar") = {"foo", "bar"},
293%% path_split("/foo/bar") = {"", "foo/bar"}.
294path_split(S) ->
295 path_split(S, []).
296
297path_split("", Acc) ->
298 {lists:reverse(Acc), ""};
299path_split("/" ++ Rest, Acc) ->
300 {lists:reverse(Acc), Rest};
301path_split([C | Rest], Acc) ->
302 path_split(Rest, [C | Acc]).
303
304
305%% @spec urlunsplit({Scheme, Netloc, Path, Query, Fragment}) -> string()
306%% @doc Assemble a URL from the 5-tuple. Path must be absolute.
307urlunsplit({Scheme, Netloc, Path, Query, Fragment}) ->
308 lists:flatten([case Scheme of "" -> ""; _ -> [Scheme, "://"] end,
309 Netloc,
310 urlunsplit_path({Path, Query, Fragment})]).
311
312%% @spec urlunsplit_path({Path, Query, Fragment}) -> string()
313%% @doc Assemble a URL path from the 3-tuple.
314urlunsplit_path({Path, Query, Fragment}) ->
315 lists:flatten([Path,
316 case Query of "" -> ""; _ -> [$? | Query] end,
317 case Fragment of "" -> ""; _ -> [$# | Fragment] end]).
318
319%% @spec urlsplit_path(Url) -> {Path, Query, Fragment}
320%% @doc Return a 3-tuple, does not expand % escapes. Only supports HTTP style
321%% paths.
322urlsplit_path(Path) ->
323 urlsplit_path(Path, []).
324
325urlsplit_path("", Acc) ->
326 {lists:reverse(Acc), "", ""};
327urlsplit_path("?" ++ Rest, Acc) ->
328 {Query, Fragment} = urlsplit_query(Rest),
329 {lists:reverse(Acc), Query, Fragment};
330urlsplit_path("#" ++ Rest, Acc) ->
331 {lists:reverse(Acc), "", Rest};
332urlsplit_path([C | Rest], Acc) ->
333 urlsplit_path(Rest, [C | Acc]).
334
335urlsplit_query(Query) ->
336 urlsplit_query(Query, []).
337
338urlsplit_query("", Acc) ->
339 {lists:reverse(Acc), ""};
340urlsplit_query("#" ++ Rest, Acc) ->
341 {lists:reverse(Acc), Rest};
342urlsplit_query([C | Rest], Acc) ->
343 urlsplit_query(Rest, [C | Acc]).
344
345%% @spec guess_mime(string()) -> string()
346%% @doc Guess the mime type of a file by the extension of its filename.
347guess_mime(File) ->
348 case mochiweb_mime:from_extension(filename:extension(File)) of
349 undefined ->
350 "text/plain";
351 Mime ->
352 Mime
353 end.
354
355%% @spec parse_header(string()) -> {Type, [{K, V}]}
356%% @doc Parse a Content-Type like header, return the main Content-Type
357%% and a property list of options.
358parse_header(String) ->
359 %% TODO: This is exactly as broken as Python's cgi module.
360 %% Should parse properly like mochiweb_cookies.
361 [Type | Parts] = [string:strip(S) || S <- string:tokens(String, ";")],
362 F = fun (S, Acc) ->
363 case lists:splitwith(fun (C) -> C =/= $= end, S) of
364 {"", _} ->
365 %% Skip anything with no name
366 Acc;
367 {_, ""} ->
368 %% Skip anything with no value
369 Acc;
370 {Name, [$\= | Value]} ->
371 [{string:to_lower(string:strip(Name)),
372 unquote_header(string:strip(Value))} | Acc]
373 end
374 end,
375 {string:to_lower(Type),
376 lists:foldr(F, [], Parts)}.
377
378unquote_header("\"" ++ Rest) ->
379 unquote_header(Rest, []);
380unquote_header(S) ->
381 S.
382
383unquote_header("", Acc) ->
384 lists:reverse(Acc);
385unquote_header("\"", Acc) ->
386 lists:reverse(Acc);
387unquote_header([$\\, C | Rest], Acc) ->
388 unquote_header(Rest, [C | Acc]);
389unquote_header([C | Rest], Acc) ->
390 unquote_header(Rest, [C | Acc]).
391
392%% @spec record_to_proplist(Record, Fields) -> proplist()
393%% @doc calls record_to_proplist/3 with a default TypeKey of '__record'
394record_to_proplist(Record, Fields) ->
395 record_to_proplist(Record, Fields, '__record').
396
397%% @spec record_to_proplist(Record, Fields, TypeKey) -> proplist()
398%% @doc Return a proplist of the given Record with each field in the
399%% Fields list set as a key with the corresponding value in the Record.
400%% TypeKey is the key that is used to store the record type
401%% Fields should be obtained by calling record_info(fields, record_type)
402%% where record_type is the record type of Record
403record_to_proplist(Record, Fields, TypeKey)
404 when tuple_size(Record) - 1 =:= length(Fields) ->
405 lists:zip([TypeKey | Fields], tuple_to_list(Record)).
406
407
408shell_quote([], Acc) ->
409 lists:reverse([$\" | Acc]);
410shell_quote([C | Rest], Acc) when C =:= $\" orelse C =:= $\` orelse
411 C =:= $\\ orelse C =:= $\$ ->
412 shell_quote(Rest, [C, $\\ | Acc]);
413shell_quote([C | Rest], Acc) ->
414 shell_quote(Rest, [C | Acc]).
415
416%% @spec parse_qvalues(string()) -> [qvalue()] | invalid_qvalue_string
417%% @type qvalue() = {media_type() | encoding() , float()}.
418%% @type media_type() = string().
419%% @type encoding() = string().
420%%
421%% @doc Parses a list (given as a string) of elements with Q values associated
422%% to them. Elements are separated by commas and each element is separated
423%% from its Q value by a semicolon. Q values are optional but when missing
424%% the value of an element is considered as 1.0. A Q value is always in the
425%% range [0.0, 1.0]. A Q value list is used for example as the value of the
426%% HTTP "Accept" and "Accept-Encoding" headers.
427%%
428%% Q values are described in section 2.9 of the RFC 2616 (HTTP 1.1).
429%%
430%% Example:
431%%
432%% parse_qvalues("gzip; q=0.5, deflate, identity;q=0.0") ->
433%% [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 0.0}]
434%%
435parse_qvalues(QValuesStr) ->
436 try
437 lists:map(
438 fun(Pair) ->
439 [Type | Params] = string:tokens(Pair, ";"),
440 NormParams = normalize_media_params(Params),
441 {Q, NonQParams} = extract_q(NormParams),
442 {string:join([string:strip(Type) | NonQParams], ";"), Q}
443 end,
444 string:tokens(string:to_lower(QValuesStr), ",")
445 )
446 catch
447 _Type:_Error ->
448 invalid_qvalue_string
449 end.
450
451normalize_media_params(Params) ->
452 {ok, Re} = re:compile("\\s"),
453 normalize_media_params(Re, Params, []).
454
455normalize_media_params(_Re, [], Acc) ->
456 lists:reverse(Acc);
457normalize_media_params(Re, [Param | Rest], Acc) ->
458 NormParam = re:replace(Param, Re, "", [global, {return, list}]),
459 normalize_media_params(Re, Rest, [NormParam | Acc]).
460
461extract_q(NormParams) ->
462 {ok, KVRe} = re:compile("^([^=]+)=([^=]+)$"),
463 {ok, QRe} = re:compile("^((?:0|1)(?:\\.\\d{1,3})?)$"),
464 extract_q(KVRe, QRe, NormParams, []).
465
466extract_q(_KVRe, _QRe, [], Acc) ->
467 {1.0, lists:reverse(Acc)};
468extract_q(KVRe, QRe, [Param | Rest], Acc) ->
469 case re:run(Param, KVRe, [{capture, [1, 2], list}]) of
470 {match, [Name, Value]} ->
471 case Name of
472 "q" ->
473 {match, [Q]} = re:run(Value, QRe, [{capture, [1], list}]),
474 QVal = case Q of
475 "0" ->
476 0.0;
477 "1" ->
478 1.0;
479 Else ->
480 list_to_float(Else)
481 end,
482 case QVal < 0.0 orelse QVal > 1.0 of
483 false ->
484 {QVal, lists:reverse(Acc) ++ Rest}
485 end;
486 _ ->
487 extract_q(KVRe, QRe, Rest, [Param | Acc])
488 end
489 end.
490
491%% @spec pick_accepted_encodings([qvalue()], [encoding()], encoding()) ->
492%% [encoding()]
493%%
494%% @doc Determines which encodings specified in the given Q values list are
495%% valid according to a list of supported encodings and a default encoding.
496%%
497%% The returned list of encodings is sorted, descendingly, according to the
498%% Q values of the given list. The last element of this list is the given
499%% default encoding unless this encoding is explicitily or implicitily
500%% marked with a Q value of 0.0 in the given Q values list.
501%% Note: encodings with the same Q value are kept in the same order as
502%% found in the input Q values list.
503%%
504%% This encoding picking process is described in section 14.3 of the
505%% RFC 2616 (HTTP 1.1).
506%%
507%% Example:
508%%
509%% pick_accepted_encodings(
510%% [{"gzip", 0.5}, {"deflate", 1.0}],
511%% ["gzip", "identity"],
512%% "identity"
513%% ) ->
514%% ["gzip", "identity"]
515%%
516pick_accepted_encodings(AcceptedEncs, SupportedEncs, DefaultEnc) ->
517 SortedQList = lists:reverse(
518 lists:sort(fun({_, Q1}, {_, Q2}) -> Q1 < Q2 end, AcceptedEncs)
519 ),
520 {Accepted, Refused} = lists:foldr(
521 fun({E, Q}, {A, R}) ->
522 case Q > 0.0 of
523 true ->
524 {[E | A], R};
525 false ->
526 {A, [E | R]}
527 end
528 end,
529 {[], []},
530 SortedQList
531 ),
532 Refused1 = lists:foldr(
533 fun(Enc, Acc) ->
534 case Enc of
535 "*" ->
536 lists:subtract(SupportedEncs, Accepted) ++ Acc;
537 _ ->
538 [Enc | Acc]
539 end
540 end,
541 [],
542 Refused
543 ),
544 Accepted1 = lists:foldr(
545 fun(Enc, Acc) ->
546 case Enc of
547 "*" ->
548 lists:subtract(SupportedEncs, Accepted ++ Refused1) ++ Acc;
549 _ ->
550 [Enc | Acc]
551 end
552 end,
553 [],
554 Accepted
555 ),
556 Accepted2 = case lists:member(DefaultEnc, Accepted1) of
557 true ->
558 Accepted1;
559 false ->
560 Accepted1 ++ [DefaultEnc]
561 end,
562 [E || E <- Accepted2, lists:member(E, SupportedEncs),
563 not lists:member(E, Refused1)].
564
565make_io(Atom) when is_atom(Atom) ->
566 atom_to_list(Atom);
567make_io(Integer) when is_integer(Integer) ->
568 integer_to_list(Integer);
569make_io(Io) when is_list(Io); is_binary(Io) ->
570 Io.
571
572%%
573%% Tests
574%%
575-include_lib("eunit/include/eunit.hrl").
576-ifdef(TEST).
577
578make_io_test() ->
579 ?assertEqual(
580 <<"atom">>,
581 iolist_to_binary(make_io(atom))),
582 ?assertEqual(
583 <<"20">>,
584 iolist_to_binary(make_io(20))),
585 ?assertEqual(
586 <<"list">>,
587 iolist_to_binary(make_io("list"))),
588 ?assertEqual(
589 <<"binary">>,
590 iolist_to_binary(make_io(<<"binary">>))),
591 ok.
592
593-record(test_record, {field1=f1, field2=f2}).
594record_to_proplist_test() ->
595 ?assertEqual(
596 [{'__record', test_record},
597 {field1, f1},
598 {field2, f2}],
599 record_to_proplist(#test_record{}, record_info(fields, test_record))),
600 ?assertEqual(
601 [{'typekey', test_record},
602 {field1, f1},
603 {field2, f2}],
604 record_to_proplist(#test_record{},
605 record_info(fields, test_record),
606 typekey)),
607 ok.
608
609shell_quote_test() ->
610 ?assertEqual(
611 "\"foo \\$bar\\\"\\`' baz\"",
612 shell_quote("foo $bar\"`' baz")),
613 ok.
614
615cmd_port_test_spool(Port, Acc) ->
616 receive
617 {Port, eof} ->
618 Acc;
619 {Port, {data, {eol, Data}}} ->
620 cmd_port_test_spool(Port, ["\n", Data | Acc]);
621 {Port, Unknown} ->
622 throw({unknown, Unknown})
623 after 1000 ->
624 throw(timeout)
625 end.
626
627cmd_port_test() ->
628 Port = cmd_port(["echo", "$bling$ `word`!"],
629 [eof, stream, {line, 4096}]),
630 Res = try lists:append(lists:reverse(cmd_port_test_spool(Port, [])))
631 after catch port_close(Port)
632 end,
633 self() ! {Port, wtf},
634 try cmd_port_test_spool(Port, [])
635 catch throw:{unknown, wtf} -> ok
636 end,
637 try cmd_port_test_spool(Port, [])
638 catch throw:timeout -> ok
639 end,
640 ?assertEqual(
641 "$bling$ `word`!\n",
642 Res).
643
644cmd_test() ->
645 ?assertEqual(
646 "$bling$ `word`!\n",
647 cmd(["echo", "$bling$ `word`!"])),
648 ok.
649
650cmd_string_test() ->
651 ?assertEqual(
652 "\"echo\" \"\\$bling\\$ \\`word\\`!\"",
653 cmd_string(["echo", "$bling$ `word`!"])),
654 ok.
655
656cmd_status_test() ->
657 ?assertEqual(
658 {0, <<"$bling$ `word`!\n">>},
659 cmd_status(["echo", "$bling$ `word`!"])),
660 ok.
661
662
663parse_header_test() ->
664 ?assertEqual(
665 {"multipart/form-data", [{"boundary", "AaB03x"}]},
666 parse_header("multipart/form-data; boundary=AaB03x")),
667 %% This tests (currently) intentionally broken behavior
668 ?assertEqual(
669 {"multipart/form-data",
670 [{"b", ""},
671 {"cgi", "is"},
672 {"broken", "true\"e"}]},
673 parse_header("multipart/form-data;b=;cgi=\"i\\s;broken=true\"e;=z;z")),
674 ok.
675
676guess_mime_test() ->
677 "text/plain" = guess_mime(""),
678 "text/plain" = guess_mime(".text"),
679 "application/zip" = guess_mime(".zip"),
680 "application/zip" = guess_mime("x.zip"),
681 "text/html" = guess_mime("x.html"),
682 "application/xhtml+xml" = guess_mime("x.xhtml"),
683 ok.
684
685path_split_test() ->
686 {"", "foo/bar"} = path_split("/foo/bar"),
687 {"foo", "bar"} = path_split("foo/bar"),
688 {"bar", ""} = path_split("bar"),
689 ok.
690
691urlsplit_test() ->
692 {"", "", "/foo", "", "bar?baz"} = urlsplit("/foo#bar?baz"),
693 {"http", "host:port", "/foo", "", "bar?baz"} =
694 urlsplit("http://host:port/foo#bar?baz"),
695 {"http", "host", "", "", ""} = urlsplit("http://host"),
696 {"", "", "/wiki/Category:Fruit", "", ""} =
697 urlsplit("/wiki/Category:Fruit"),
698 ok.
699
700urlsplit_path_test() ->
701 {"/foo/bar", "", ""} = urlsplit_path("/foo/bar"),
702 {"/foo", "baz", ""} = urlsplit_path("/foo?baz"),
703 {"/foo", "", "bar?baz"} = urlsplit_path("/foo#bar?baz"),
704 {"/foo", "", "bar?baz#wibble"} = urlsplit_path("/foo#bar?baz#wibble"),
705 {"/foo", "bar", "baz"} = urlsplit_path("/foo?bar#baz"),
706 {"/foo", "bar?baz", "baz"} = urlsplit_path("/foo?bar?baz#baz"),
707 ok.
708
709urlunsplit_test() ->
710 "/foo#bar?baz" = urlunsplit({"", "", "/foo", "", "bar?baz"}),
711 "http://host:port/foo#bar?baz" =
712 urlunsplit({"http", "host:port", "/foo", "", "bar?baz"}),
713 ok.
714
715urlunsplit_path_test() ->
716 "/foo/bar" = urlunsplit_path({"/foo/bar", "", ""}),
717 "/foo?baz" = urlunsplit_path({"/foo", "baz", ""}),
718 "/foo#bar?baz" = urlunsplit_path({"/foo", "", "bar?baz"}),
719 "/foo#bar?baz#wibble" = urlunsplit_path({"/foo", "", "bar?baz#wibble"}),
720 "/foo?bar#baz" = urlunsplit_path({"/foo", "bar", "baz"}),
721 "/foo?bar?baz#baz" = urlunsplit_path({"/foo", "bar?baz", "baz"}),
722 ok.
723
724join_test() ->
725 ?assertEqual("foo,bar,baz",
726 join(["foo", "bar", "baz"], $,)),
727 ?assertEqual("foo,bar,baz",
728 join(["foo", "bar", "baz"], ",")),
729 ?assertEqual("foo bar",
730 join([["foo", " bar"]], ",")),
731 ?assertEqual("foo bar,baz",
732 join([["foo", " bar"], "baz"], ",")),
733 ?assertEqual("foo",
734 join(["foo"], ",")),
735 ?assertEqual("foobarbaz",
736 join(["foo", "bar", "baz"], "")),
737 ?assertEqual("foo" ++ [<<>>] ++ "bar" ++ [<<>>] ++ "baz",
738 join(["foo", "bar", "baz"], <<>>)),
739 ?assertEqual("foobar" ++ [<<"baz">>],
740 join(["foo", "bar", <<"baz">>], "")),
741 ?assertEqual("",
742 join([], "any")),
743 ok.
744
745quote_plus_test() ->
746 "foo" = quote_plus(foo),
747 "1" = quote_plus(1),
748 "1.1" = quote_plus(1.1),
749 "foo" = quote_plus("foo"),
750 "foo+bar" = quote_plus("foo bar"),
751 "foo%0A" = quote_plus("foo\n"),
752 "foo%0A" = quote_plus("foo\n"),
753 "foo%3B%26%3D" = quote_plus("foo;&="),
754 "foo%3B%26%3D" = quote_plus(<<"foo;&=">>),
755 ok.
756
757unquote_test() ->
758 ?assertEqual("foo bar",
759 unquote("foo+bar")),
760 ?assertEqual("foo bar",
761 unquote("foo%20bar")),
762 ?assertEqual("foo\r\n",
763 unquote("foo%0D%0A")),
764 ?assertEqual("foo\r\n",
765 unquote(<<"foo%0D%0A">>)),
766 ok.
767
768urlencode_test() ->
769 "foo=bar&baz=wibble+%0D%0A&z=1" = urlencode([{foo, "bar"},
770 {"baz", "wibble \r\n"},
771 {z, 1}]),
772 ok.
773
774parse_qs_test() ->
775 ?assertEqual(
776 [{"foo", "bar"}, {"baz", "wibble \r\n"}, {"z", "1"}],
777 parse_qs("foo=bar&baz=wibble+%0D%0a&z=1")),
778 ?assertEqual(
779 [{"", "bar"}, {"baz", "wibble \r\n"}, {"z", ""}],
780 parse_qs("=bar&baz=wibble+%0D%0a&z=")),
781 ?assertEqual(
782 [{"foo", "bar"}, {"baz", "wibble \r\n"}, {"z", "1"}],
783 parse_qs(<<"foo=bar&baz=wibble+%0D%0a&z=1">>)),
784 ?assertEqual(
785 [],
786 parse_qs("")),
787 ?assertEqual(
788 [{"foo", ""}, {"bar", ""}, {"baz", ""}],
789 parse_qs("foo;bar&baz")),
790 ok.
791
792partition_test() ->
793 {"foo", "", ""} = partition("foo", "/"),
794 {"foo", "/", "bar"} = partition("foo/bar", "/"),
795 {"foo", "/", ""} = partition("foo/", "/"),
796 {"", "/", "bar"} = partition("/bar", "/"),
797 {"f", "oo/ba", "r"} = partition("foo/bar", "oo/ba"),
798 ok.
799
800safe_relative_path_test() ->
801 "foo" = safe_relative_path("foo"),
802 "foo/" = safe_relative_path("foo/"),
803 "foo" = safe_relative_path("foo/bar/.."),
804 "bar" = safe_relative_path("foo/../bar"),
805 "bar/" = safe_relative_path("foo/../bar/"),
806 "" = safe_relative_path("foo/.."),
807 "" = safe_relative_path("foo/../"),
808 undefined = safe_relative_path("/foo"),
809 undefined = safe_relative_path("../foo"),
810 undefined = safe_relative_path("foo/../.."),
811 undefined = safe_relative_path("foo//"),
812 ok.
813
814parse_qvalues_test() ->
815 [] = parse_qvalues(""),
816 [{"identity", 0.0}] = parse_qvalues("identity;q=0"),
817 [{"identity", 0.0}] = parse_qvalues("identity ;q=0"),
818 [{"identity", 0.0}] = parse_qvalues(" identity; q =0 "),
819 [{"identity", 0.0}] = parse_qvalues("identity ; q = 0"),
820 [{"identity", 0.0}] = parse_qvalues("identity ; q= 0.0"),
821 [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
822 "gzip,deflate,identity;q=0.0"
823 ),
824 [{"deflate", 1.0}, {"gzip", 1.0}, {"identity", 0.0}] = parse_qvalues(
825 "deflate,gzip,identity;q=0.0"
826 ),
827 [{"gzip", 1.0}, {"deflate", 1.0}, {"gzip", 1.0}, {"identity", 0.0}] =
828 parse_qvalues("gzip,deflate,gzip,identity;q=0"),
829 [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
830 "gzip, deflate , identity; q=0.0"
831 ),
832 [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
833 "gzip; q=1, deflate;q=1.0, identity;q=0.0"
834 ),
835 [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
836 "gzip; q=0.5, deflate;q=1.0, identity;q=0"
837 ),
838 [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
839 "gzip; q=0.5, deflate , identity;q=0.0"
840 ),
841 [{"gzip", 0.5}, {"deflate", 0.8}, {"identity", 0.0}] = parse_qvalues(
842 "gzip; q=0.5, deflate;q=0.8, identity;q=0.0"
843 ),
844 [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 1.0}] = parse_qvalues(
845 "gzip; q=0.5,deflate,identity"
846 ),
847 [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 1.0}, {"identity", 1.0}] =
848 parse_qvalues("gzip; q=0.5,deflate,identity, identity "),
849 [{"text/html;level=1", 1.0}, {"text/plain", 0.5}] =
850 parse_qvalues("text/html;level=1, text/plain;q=0.5"),
851 [{"text/html;level=1", 0.3}, {"text/plain", 1.0}] =
852 parse_qvalues("text/html;level=1;q=0.3, text/plain"),
853 [{"text/html;level=1", 0.3}, {"text/plain", 1.0}] =
854 parse_qvalues("text/html; level = 1; q = 0.3, text/plain"),
855 [{"text/html;level=1", 0.3}, {"text/plain", 1.0}] =
856 parse_qvalues("text/html;q=0.3;level=1, text/plain"),
857 invalid_qvalue_string = parse_qvalues("gzip; q=1.1, deflate"),
858 invalid_qvalue_string = parse_qvalues("gzip; q=0.5, deflate;q=2"),
859 invalid_qvalue_string = parse_qvalues("gzip, deflate;q=AB"),
860 invalid_qvalue_string = parse_qvalues("gzip; q=2.1, deflate"),
861 invalid_qvalue_string = parse_qvalues("gzip; q=0.1234, deflate"),
862 invalid_qvalue_string = parse_qvalues("text/html;level=1;q=0.3, text/html;level"),
863 ok.
864
865pick_accepted_encodings_test() ->
866 ["identity"] = pick_accepted_encodings(
867 [],
868 ["gzip", "identity"],
869 "identity"
870 ),
871 ["gzip", "identity"] = pick_accepted_encodings(
872 [{"gzip", 1.0}],
873 ["gzip", "identity"],
874 "identity"
875 ),
876 ["identity"] = pick_accepted_encodings(
877 [{"gzip", 0.0}],
878 ["gzip", "identity"],
879 "identity"
880 ),
881 ["gzip", "identity"] = pick_accepted_encodings(
882 [{"gzip", 1.0}, {"deflate", 1.0}],
883 ["gzip", "identity"],
884 "identity"
885 ),
886 ["gzip", "identity"] = pick_accepted_encodings(
887 [{"gzip", 0.5}, {"deflate", 1.0}],
888 ["gzip", "identity"],
889 "identity"
890 ),
891 ["identity"] = pick_accepted_encodings(
892 [{"gzip", 0.0}, {"deflate", 0.0}],
893 ["gzip", "identity"],
894 "identity"
895 ),
896 ["gzip"] = pick_accepted_encodings(
897 [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}],
898 ["gzip", "identity"],
899 "identity"
900 ),
901 ["gzip", "deflate", "identity"] = pick_accepted_encodings(
902 [{"gzip", 1.0}, {"deflate", 1.0}],
903 ["gzip", "deflate", "identity"],
904 "identity"
905 ),
906 ["gzip", "deflate"] = pick_accepted_encodings(
907 [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}],
908 ["gzip", "deflate", "identity"],
909 "identity"
910 ),
911 ["deflate", "gzip", "identity"] = pick_accepted_encodings(
912 [{"gzip", 0.2}, {"deflate", 1.0}],
913 ["gzip", "deflate", "identity"],
914 "identity"
915 ),
916 ["deflate", "deflate", "gzip", "identity"] = pick_accepted_encodings(
917 [{"gzip", 0.2}, {"deflate", 1.0}, {"deflate", 1.0}],
918 ["gzip", "deflate", "identity"],
919 "identity"
920 ),
921 ["deflate", "gzip", "gzip", "identity"] = pick_accepted_encodings(
922 [{"gzip", 0.2}, {"deflate", 1.0}, {"gzip", 1.0}],
923 ["gzip", "deflate", "identity"],
924 "identity"
925 ),
926 ["gzip", "deflate", "gzip", "identity"] = pick_accepted_encodings(
927 [{"gzip", 0.2}, {"deflate", 0.9}, {"gzip", 1.0}],
928 ["gzip", "deflate", "identity"],
929 "identity"
930 ),
931 [] = pick_accepted_encodings(
932 [{"*", 0.0}],
933 ["gzip", "deflate", "identity"],
934 "identity"
935 ),
936 ["gzip", "deflate", "identity"] = pick_accepted_encodings(
937 [{"*", 1.0}],
938 ["gzip", "deflate", "identity"],
939 "identity"
940 ),
941 ["gzip", "deflate", "identity"] = pick_accepted_encodings(
942 [{"*", 0.6}],
943 ["gzip", "deflate", "identity"],
944 "identity"
945 ),
946 ["gzip"] = pick_accepted_encodings(
947 [{"gzip", 1.0}, {"*", 0.0}],
948 ["gzip", "deflate", "identity"],
949 "identity"
950 ),
951 ["gzip", "deflate"] = pick_accepted_encodings(
952 [{"gzip", 1.0}, {"deflate", 0.6}, {"*", 0.0}],
953 ["gzip", "deflate", "identity"],
954 "identity"
955 ),
956 ["deflate", "gzip"] = pick_accepted_encodings(
957 [{"gzip", 0.5}, {"deflate", 1.0}, {"*", 0.0}],
958 ["gzip", "deflate", "identity"],
959 "identity"
960 ),
961 ["gzip", "identity"] = pick_accepted_encodings(
962 [{"deflate", 0.0}, {"*", 1.0}],
963 ["gzip", "deflate", "identity"],
964 "identity"
965 ),
966 ["gzip", "identity"] = pick_accepted_encodings(
967 [{"*", 1.0}, {"deflate", 0.0}],
968 ["gzip", "deflate", "identity"],
969 "identity"
970 ),
971 ok.
972
973-endif.
9740
=== removed directory '.pc/improve_script_url_validation.patch'
=== removed directory '.pc/improve_script_url_validation.patch/share'
=== removed directory '.pc/improve_script_url_validation.patch/share/www'
=== removed directory '.pc/improve_script_url_validation.patch/share/www/script'
=== removed file '.pc/improve_script_url_validation.patch/share/www/script/couch_test_runner.js'
--- .pc/improve_script_url_validation.patch/share/www/script/couch_test_runner.js 2013-01-18 22:04:32 +0000
+++ .pc/improve_script_url_validation.patch/share/www/script/couch_test_runner.js 1970-01-01 00:00:00 +0000
@@ -1,472 +0,0 @@
1// Licensed under the Apache License, Version 2.0 (the "License"); you may not
2// use this file except in compliance with the License. You may obtain a copy of
3// the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10// License for the specific language governing permissions and limitations under
11// the License.
12
13// *********************** Test Framework of Sorts ************************* //
14
15
16function loadScript(url) {
17 // disallow loading remote URLs
18 if((url.substr(0, 7) == "http://")
19 || (url.substr(0, 2) == "//")
20 || (url.substr(0, 5) == "data:")
21 || (url.substr(0, 11) == "javascript:")) {
22 throw "Not loading remote test scripts";
23 }
24 if (typeof document != "undefined") document.write('<script src="'+url+'"></script>');
25};
26
27function patchTest(fun) {
28 var source = fun.toString();
29 var output = "";
30 var i = 0;
31 var testMarker = "T(";
32 while (i < source.length) {
33 var testStart = source.indexOf(testMarker, i);
34 if (testStart == -1) {
35 output = output + source.substring(i, source.length);
36 break;
37 }
38 var testEnd = source.indexOf(");", testStart);
39 var testCode = source.substring(testStart + testMarker.length, testEnd);
40 output += source.substring(i, testStart) + "T(" + testCode + "," + JSON.stringify(testCode);
41 i = testEnd;
42 }
43 try {
44 return eval("(" + output + ")");
45 } catch (e) {
46 return null;
47 }
48}
49
50function runAllTests() {
51 var rows = $("#tests tbody.content tr");
52 $("td", rows).text("");
53 $("td.status", rows).removeClass("error").removeClass("failure").removeClass("success").text("not run");
54 var offset = 0;
55 function runNext() {
56 if (offset < rows.length) {
57 var row = rows.get(offset);
58 runTest($("th button", row).get(0), function() {
59 offset += 1;
60 setTimeout(runNext, 100);
61 }, false, true);
62 } else {
63 saveTestReport();
64 }
65 }
66 runNext();
67}
68
69var numFailures = 0;
70var currentRow = null;
71
72function runTest(button, callback, debug, noSave) {
73
74 // offer to save admins
75 if (currentRow != null) {
76 alert("Can not run multiple tests simultaneously.");
77 return;
78 }
79 var row = currentRow = $(button).parents("tr").get(0);
80 $("td.status", row).removeClass("error").removeClass("failure").removeClass("success");
81 $("td", row).text("");
82 $("#toolbar li.current").text("Running: "+row.id);
83 var testFun = couchTests[row.id];
84 function run() {
85 numFailures = 0;
86 var start = new Date().getTime();
87 try {
88 if (debug == undefined || !debug) {
89 testFun = patchTest(testFun) || testFun;
90 }
91 testFun(debug);
92 var status = numFailures > 0 ? "failure" : "success";
93 } catch (e) {
94 var status = "error";
95 if ($("td.details ol", row).length == 0) {
96 $("<ol></ol>").appendTo($("td.details", row));
97 }
98 $("<li><b>Exception raised:</b> <code class='error'></code></li>")
99 .find("code").text(JSON.stringify(e)).end()
100 .appendTo($("td.details ol", row));
101 if (debug) {
102 currentRow = null;
103 throw e;
104 }
105 }
106 if ($("td.details ol", row).length) {
107 $("<a href='#'>Run with debugger</a>").click(function() {
108 runTest(this, undefined, true);
109 }).prependTo($("td.details ol", row));
110 }
111 var duration = new Date().getTime() - start;
112 $("td.status", row).removeClass("running").addClass(status).text(status);
113 $("td.duration", row).text(duration + "ms");
114 $("#toolbar li.current").text("Finished: "+row.id);
115 updateTestsFooter();
116 currentRow = null;
117 if (callback) callback();
118 if (!noSave) saveTestReport();
119 }
120 $("td.status", row).addClass("running").text("running…");
121 setTimeout(run, 100);
122}
123
124function showSource(cell) {
125 var name = $(cell).text();
126 var win = window.open("", name, "width=700,height=500,resizable=yes,scrollbars=yes");
127 win.document.location = "script/test/" + name + ".js";
128}
129
130var readyToRun;
131function setupAdminParty(fun) {
132 if (readyToRun) {
133 fun();
134 } else {
135 function removeAdmins(confs, doneFun) {
136 // iterate through the config and remove current user last
137 // current user is at front of list
138 var remove = confs.pop();
139 if (remove) {
140 $.couch.config({
141 success : function() {
142 removeAdmins(confs, doneFun);
143 }
144 }, "admins", remove[0], null);
145 } else {
146 doneFun();
147 }
148 };
149 $.couch.session({
150 success : function(resp) {
151 var userCtx = resp.userCtx;
152 if (userCtx.name && userCtx.roles.indexOf("_admin") != -1) {
153 // admin but not admin party. dialog offering to make admin party
154 $.showDialog("dialog/_admin_party.html", {
155 submit: function(data, callback) {
156 $.couch.config({
157 success : function(conf) {
158 var meAdmin, adminConfs = [];
159 for (var name in conf) {
160 if (name == userCtx.name) {
161 meAdmin = [name, conf[name]];
162 } else {
163 adminConfs.push([name, conf[name]]);
164 }
165 }
166 adminConfs.unshift(meAdmin);
167 removeAdmins(adminConfs, function() {
168 callback();
169 $.futon.session.sidebar();
170 readyToRun = true;
171 setTimeout(fun, 500);
172 });
173 }
174 }, "admins");
175 }
176 });
177 } else if (userCtx.roles.indexOf("_admin") != -1) {
178 // admin party!
179 readyToRun = true;
180 fun();
181 } else {
182 // not an admin
183 alert("Error: You need to be an admin to run the tests.");
184 };
185 }
186 });
187 }
188};
189
190function updateTestsListing() {
191 for (var name in couchTests) {
192 var testFunction = couchTests[name];
193 var row = $("<tr><th></th><td></td><td></td><td></td></tr>")
194 .find("th").text(name).attr("title", "Show source").click(function() {
195 showSource(this);
196 }).end()
197 .find("td:nth(0)").addClass("status").text("not run").end()
198 .find("td:nth(1)").addClass("duration").end()
199 .find("td:nth(2)").addClass("details").end();
200 $("<button type='button' class='run' title='Run test'></button>").click(function() {
201 this.blur();
202 var self = this;
203 // check for admin party
204 setupAdminParty(function() {
205 runTest(self);
206 });
207 return false;
208 }).prependTo(row.find("th"));
209 row.attr("id", name).appendTo("#tests tbody.content");
210 }
211 $("#tests tr").removeClass("odd").filter(":odd").addClass("odd");
212 updateTestsFooter();
213}
214
215function updateTestsFooter() {
216 var tests = $("#tests tbody.content tr td.status");
217 var testsRun = tests.filter(".success, .error, .failure");
218 var testsFailed = testsRun.not(".success");
219 var totalDuration = 0;
220 $("#tests tbody.content tr td.duration:contains('ms')").each(function() {
221 var text = $(this).text();
222 totalDuration += parseInt(text.substr(0, text.length - 2), 10);
223 });
224 $("#tests tbody.footer td").html("<span>"+testsRun.length + " of " + tests.length +
225 " test(s) run, " + testsFailed.length + " failures (" +
226 totalDuration + " ms)</span> ");
227}
228
229// make report and save to local db
230// display how many reports need replicating to the mothership
231// have button to replicate them
232
233function saveTestReport(report) {
234 var report = makeTestReport();
235 if (report) {
236 var db = $.couch.db("test_suite_reports");
237 var saveReport = function(db_info) {
238 report.db = db_info;
239 $.couch.info({success : function(node_info) {
240 report.node = node_info;
241 db.saveDoc(report);
242 }});
243 };
244 var createDb = function() {
245 db.create({success: function() {
246 db.info({success:saveReport});
247 }});
248 };
249 db.info({error: createDb, success:saveReport});
250 }
251};
252
253function makeTestReport() {
254 var report = {};
255 report.summary = $("#tests tbody.footer td").text();
256 report.platform = testPlatform();
257 var date = new Date();
258 report.timestamp = date.getTime();
259 report.timezone = date.getTimezoneOffset();
260 report.tests = [];
261 $("#tests tbody.content tr").each(function() {
262 var status = $("td.status", this).text();
263 if (status != "not run") {
264 var test = {};
265 test.name = this.id;
266 test.status = status;
267 test.duration = parseInt($("td.duration", this).text());
268 test.details = [];
269 $("td.details li", this).each(function() {
270 test.details.push($(this).text());
271 });
272 if (test.details.length == 0) {
273 delete test.details;
274 }
275 report.tests.push(test);
276 }
277 });
278 if (report.tests.length > 0) return report;
279};
280
281function testPlatform() {
282 var b = $.browser;
283 var bs = ["mozilla", "msie", "opera", "safari"];
284 for (var i=0; i < bs.length; i++) {
285 if (b[bs[i]]) {
286 return {"browser" : bs[i], "version" : b.version};
287 }
288 };
289 return {"browser" : "undetected"};
290}
291
292
293function reportTests() {
294 // replicate the database to couchdb.couchdb.org
295}
296
297// Use T to perform a test that returns false on failure and if the test fails,
298// display the line that failed.
299// Example:
300// T(MyValue==1);
301function T(arg1, arg2, testName) {
302 if (!arg1) {
303 if (currentRow) {
304 if ($("td.details ol", currentRow).length == 0) {
305 $("<ol></ol>").appendTo($("td.details", currentRow));
306 }
307 var message = (arg2 != null ? arg2 : arg1).toString();
308 $("<li><b>Assertion " + (testName ? "'" + testName + "'" : "") + " failed:</b> <code class='failure'></code></li>")
309 .find("code").text(message).end()
310 .appendTo($("td.details ol", currentRow));
311 }
312 numFailures += 1;
313 }
314}
315
316function TIsnull(actual, testName) {
317 T(actual === null, "expected 'null', got '"
318 + repr(actual) + "'", testName);
319}
320
321function TEquals(expected, actual, testName) {
322 T(equals(expected, actual), "expected '" + repr(expected) +
323 "', got '" + repr(actual) + "'", testName);
324}
325
326function TEqualsIgnoreCase(expected, actual, testName) {
327 T(equals(expected.toUpperCase(), actual.toUpperCase()), "expected '" + repr(expected) +
328 "', got '" + repr(actual) + "'", testName);
329}
330
331function equals(a,b) {
332 if (a === b) return true;
333 try {
334 return repr(a) === repr(b);
335 } catch (e) {
336 return false;
337 }
338}
339
340function repr(val) {
341 if (val === undefined) {
342 return null;
343 } else if (val === null) {
344 return "null";
345 } else {
346 return JSON.stringify(val);
347 }
348}
349
350function makeDocs(start, end, templateDoc) {
351 var templateDocSrc = templateDoc ? JSON.stringify(templateDoc) : "{}";
352 if (end === undefined) {
353 end = start;
354 start = 0;
355 }
356 var docs = [];
357 for (var i = start; i < end; i++) {
358 var newDoc = eval("(" + templateDocSrc + ")");
359 newDoc._id = (i).toString();
360 newDoc.integer = i;
361 newDoc.string = (i).toString();
362 docs.push(newDoc);
363 }
364 return docs;
365}
366
367function run_on_modified_server(settings, fun) {
368 try {
369 // set the settings
370 for(var i=0; i < settings.length; i++) {
371 var s = settings[i];
372 var xhr = CouchDB.request("PUT", "/_config/" + s.section + "/" + s.key, {
373 body: JSON.stringify(s.value),
374 headers: {"X-Couch-Persist": "false"}
375 });
376 CouchDB.maybeThrowError(xhr);
377 s.oldValue = xhr.responseText;
378 }
379 // run the thing
380 fun();
381 } finally {
382 // unset the settings
383 for(var j=0; j < i; j++) {
384 var s = settings[j];
385 if(s.oldValue == "\"\"\n") { // unset value
386 CouchDB.request("DELETE", "/_config/" + s.section + "/" + s.key, {
387 headers: {"X-Couch-Persist": "false"}
388 });
389 } else {
390 CouchDB.request("PUT", "/_config/" + s.section + "/" + s.key, {
391 body: s.oldValue,
392 headers: {"X-Couch-Persist": "false"}
393 });
394 }
395 }
396 }
397}
398
399function stringFun(fun) {
400 var string = fun.toSource ? fun.toSource() : "(" + fun.toString() + ")";
401 return string;
402}
403
404function waitForSuccess(fun, tag) {
405 var start = new Date();
406 while(true) {
407 if (new Date() - start > 5000) {
408 throw("timeout: "+tag);
409 } else {
410 try {
411 fun();
412 break;
413 } catch (e) {}
414 // sync http req allow async req to happen
415 CouchDB.request("GET", "/test_suite_db/?tag="+encodeURIComponent(tag));
416 }
417 }
418}
419
420function waitForRestart() {
421 var waiting = true;
422 // Wait for the server to go down but don't
423 // wait too long because we might miss the
424 // the unavailable period.
425 var count = 25;
426 while (waiting && count > 0) {
427 count--;
428 try {
429 CouchDB.request("GET", "/");
430 } catch(e) {
431 waiting = false;
432 }
433 }
434 // Wait for it to come back up
435 waiting = true;
436 while (waiting) {
437 try {
438 CouchDB.request("GET", "/");
439 waiting = false;
440 } catch(e) {
441 // the request will fail until restart completes
442 }
443 }
444};
445
446function restartServer() {
447 var xhr;
448 try {
449 CouchDB.request("POST", "/_restart");
450 } catch(e) {
451 // this request may sometimes fail
452 }
453 waitForRestart();
454}
455
456// legacy functions for CouchDB < 1.2.0
457// we keep them to make sure we keep BC
458CouchDB.user_prefix = "org.couchdb.user:";
459
460CouchDB.prepareUserDoc = function(user_doc, new_password) {
461 user_doc._id = user_doc._id || CouchDB.user_prefix + user_doc.name;
462 if (new_password) {
463 // handle the password crypto
464 user_doc.salt = CouchDB.newUuids(1)[0];
465 user_doc.password_sha = hex_sha1(new_password + user_doc.salt);
466 }
467 user_doc.type = "user";
468 if (!user_doc.roles) {
469 user_doc.roles = [];
470 }
471 return user_doc;
472};
4730
=== removed directory '.pc/include_a_comment_before_jsonp_output.patch'
=== removed directory '.pc/include_a_comment_before_jsonp_output.patch/src'
=== removed directory '.pc/include_a_comment_before_jsonp_output.patch/src/couchdb'
=== removed file '.pc/include_a_comment_before_jsonp_output.patch/src/couchdb/couch_httpd.erl'
--- .pc/include_a_comment_before_jsonp_output.patch/src/couchdb/couch_httpd.erl 2013-01-18 22:04:32 +0000
+++ .pc/include_a_comment_before_jsonp_output.patch/src/couchdb/couch_httpd.erl 1970-01-01 00:00:00 +0000
@@ -1,1081 +0,0 @@
1% Licensed under the Apache License, Version 2.0 (the "License"); you may not
2% use this file except in compliance with the License. You may obtain a copy of
3% the License at
4%
5% http://www.apache.org/licenses/LICENSE-2.0
6%
7% Unless required by applicable law or agreed to in writing, software
8% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10% License for the specific language governing permissions and limitations under
11% the License.
12
13-module(couch_httpd).
14-include("couch_db.hrl").
15
16-export([start_link/0, start_link/1, stop/0, config_change/2,
17 handle_request/5]).
18
19-export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,qs_json_value/3]).
20-export([path/1,absolute_uri/2,body_length/1]).
21-export([verify_is_server_admin/1,unquote/1,quote/1,recv/2,recv_chunked/4,error_info/1]).
22-export([make_fun_spec_strs/1]).
23-export([make_arity_1_fun/1, make_arity_2_fun/1, make_arity_3_fun/1]).
24-export([parse_form/1,json_body/1,json_body_obj/1,body/1,doc_etag/1, make_etag/1, etag_respond/3]).
25-export([primary_header_value/2,partition/1,serve_file/3,serve_file/4, server_header/0]).
26-export([start_chunked_response/3,send_chunk/2,log_request/2]).
27-export([start_response_length/4, start_response/3, send/2]).
28-export([start_json_response/2, start_json_response/3, end_json_response/1]).
29-export([send_response/4,send_method_not_allowed/2,send_error/4, send_redirect/2,send_chunked_error/2]).
30-export([send_json/2,send_json/3,send_json/4,last_chunk/1,parse_multipart_request/3]).
31-export([accepted_encodings/1,handle_request_int/5,validate_referer/1,validate_ctype/2]).
32
33start_link() ->
34 start_link(http).
35start_link(http) ->
36 Port = couch_config:get("httpd", "port", "5984"),
37 start_link(?MODULE, [{port, Port}]);
38start_link(https) ->
39 Port = couch_config:get("ssl", "port", "6984"),
40 CertFile = couch_config:get("ssl", "cert_file", nil),
41 KeyFile = couch_config:get("ssl", "key_file", nil),
42 Options = case CertFile /= nil andalso KeyFile /= nil of
43 true ->
44 SslOpts = [{certfile, CertFile}, {keyfile, KeyFile}],
45
46 %% set password if one is needed for the cert
47 SslOpts1 = case couch_config:get("ssl", "password", nil) of
48 nil -> SslOpts;
49 Password ->
50 SslOpts ++ [{password, Password}]
51 end,
52 % do we verify certificates ?
53 FinalSslOpts = case couch_config:get("ssl",
54 "verify_ssl_certificates", "false") of
55 "false" -> SslOpts1;
56 "true" ->
57 case couch_config:get("ssl",
58 "cacert_file", nil) of
59 nil ->
60 io:format("Verify SSL certificate "
61 ++"enabled but file containing "
62 ++"PEM encoded CA certificates is "
63 ++"missing", []),
64 throw({error, missing_cacerts});
65 CaCertFile ->
66 Depth = list_to_integer(couch_config:get("ssl",
67 "ssl_certificate_max_depth",
68 "1")),
69 FinalOpts = [
70 {cacertfile, CaCertFile},
71 {depth, Depth},
72 {verify, verify_peer}],
73 % allows custom verify fun.
74 case couch_config:get("ssl",
75 "verify_fun", nil) of
76 nil -> FinalOpts;
77 SpecStr ->
78 FinalOpts
79 ++ [{verify_fun, make_arity_3_fun(SpecStr)}]
80 end
81 end
82 end,
83
84 [{port, Port},
85 {ssl, true},
86 {ssl_opts, FinalSslOpts}];
87 false ->
88 io:format("SSL enabled but PEM certificates are missing.", []),
89 throw({error, missing_certs})
90 end,
91 start_link(https, Options).
92start_link(Name, Options) ->
93 % read config and register for configuration changes
94
95 % just stop if one of the config settings change. couch_server_sup
96 % will restart us and then we will pick up the new settings.
97
98 BindAddress = couch_config:get("httpd", "bind_address", any),
99 DefaultSpec = "{couch_httpd_db, handle_request}",
100 DefaultFun = make_arity_1_fun(
101 couch_config:get("httpd", "default_handler", DefaultSpec)
102 ),
103
104 UrlHandlersList = lists:map(
105 fun({UrlKey, SpecStr}) ->
106 {?l2b(UrlKey), make_arity_1_fun(SpecStr)}
107 end, couch_config:get("httpd_global_handlers")),
108
109 DbUrlHandlersList = lists:map(
110 fun({UrlKey, SpecStr}) ->
111 {?l2b(UrlKey), make_arity_2_fun(SpecStr)}
112 end, couch_config:get("httpd_db_handlers")),
113
114 DesignUrlHandlersList = lists:map(
115 fun({UrlKey, SpecStr}) ->
116 {?l2b(UrlKey), make_arity_3_fun(SpecStr)}
117 end, couch_config:get("httpd_design_handlers")),
118
119 UrlHandlers = dict:from_list(UrlHandlersList),
120 DbUrlHandlers = dict:from_list(DbUrlHandlersList),
121 DesignUrlHandlers = dict:from_list(DesignUrlHandlersList),
122 {ok, ServerOptions} = couch_util:parse_term(
123 couch_config:get("httpd", "server_options", "[]")),
124 {ok, SocketOptions} = couch_util:parse_term(
125 couch_config:get("httpd", "socket_options", "[]")),
126
127 set_auth_handlers(),
128
129 Loop = fun(Req)->
130 case SocketOptions of
131 [] ->
132 ok;
133 _ ->
134 ok = mochiweb_socket:setopts(Req:get(socket), SocketOptions)
135 end,
136 apply(?MODULE, handle_request, [
137 Req, DefaultFun, UrlHandlers, DbUrlHandlers, DesignUrlHandlers
138 ])
139 end,
140
141 % set mochiweb options
142 FinalOptions = lists:append([Options, ServerOptions, [
143 {loop, Loop},
144 {name, Name},
145 {ip, BindAddress}]]),
146
147 % launch mochiweb
148 {ok, Pid} = case mochiweb_http:start(FinalOptions) of
149 {ok, MochiPid} ->
150 {ok, MochiPid};
151 {error, Reason} ->
152 io:format("Failure to start Mochiweb: ~s~n",[Reason]),
153 throw({error, Reason})
154 end,
155
156 ok = couch_config:register(fun ?MODULE:config_change/2, Pid),
157 {ok, Pid}.
158
159
160stop() ->
161 mochiweb_http:stop(couch_httpd),
162 mochiweb_http:stop(https).
163
164config_change("httpd", "bind_address") ->
165 ?MODULE:stop();
166config_change("httpd", "port") ->
167 ?MODULE:stop();
168config_change("httpd", "default_handler") ->
169 ?MODULE:stop();
170config_change("httpd", "server_options") ->
171 ?MODULE:stop();
172config_change("httpd", "socket_options") ->
173 ?MODULE:stop();
174config_change("httpd", "authentication_handlers") ->
175 set_auth_handlers();
176config_change("httpd_global_handlers", _) ->
177 ?MODULE:stop();
178config_change("httpd_db_handlers", _) ->
179 ?MODULE:stop();
180config_change("ssl", _) ->
181 ?MODULE:stop().
182
183set_auth_handlers() ->
184 AuthenticationSrcs = make_fun_spec_strs(
185 couch_config:get("httpd", "authentication_handlers", "")),
186 AuthHandlers = lists:map(
187 fun(A) -> {make_arity_1_fun(A), ?l2b(A)} end, AuthenticationSrcs),
188 ok = application:set_env(couch, auth_handlers, AuthHandlers).
189
190% SpecStr is a string like "{my_module, my_fun}"
191% or "{my_module, my_fun, <<"my_arg">>}"
192make_arity_1_fun(SpecStr) ->
193 case couch_util:parse_term(SpecStr) of
194 {ok, {Mod, Fun, SpecArg}} ->
195 fun(Arg) -> Mod:Fun(Arg, SpecArg) end;
196 {ok, {Mod, Fun}} ->
197 fun(Arg) -> Mod:Fun(Arg) end
198 end.
199
200make_arity_2_fun(SpecStr) ->
201 case couch_util:parse_term(SpecStr) of
202 {ok, {Mod, Fun, SpecArg}} ->
203 fun(Arg1, Arg2) -> Mod:Fun(Arg1, Arg2, SpecArg) end;
204 {ok, {Mod, Fun}} ->
205 fun(Arg1, Arg2) -> Mod:Fun(Arg1, Arg2) end
206 end.
207
208make_arity_3_fun(SpecStr) ->
209 case couch_util:parse_term(SpecStr) of
210 {ok, {Mod, Fun, SpecArg}} ->
211 fun(Arg1, Arg2, Arg3) -> Mod:Fun(Arg1, Arg2, Arg3, SpecArg) end;
212 {ok, {Mod, Fun}} ->
213 fun(Arg1, Arg2, Arg3) -> Mod:Fun(Arg1, Arg2, Arg3) end
214 end.
215
216% SpecStr is "{my_module, my_fun}, {my_module2, my_fun2}"
217make_fun_spec_strs(SpecStr) ->
218 re:split(SpecStr, "(?<=})\\s*,\\s*(?={)", [{return, list}]).
219
220handle_request(MochiReq, DefaultFun, UrlHandlers, DbUrlHandlers,
221 DesignUrlHandlers) ->
222
223 MochiReq1 = couch_httpd_vhost:dispatch_host(MochiReq),
224
225 handle_request_int(MochiReq1, DefaultFun,
226 UrlHandlers, DbUrlHandlers, DesignUrlHandlers).
227
228handle_request_int(MochiReq, DefaultFun,
229 UrlHandlers, DbUrlHandlers, DesignUrlHandlers) ->
230 Begin = now(),
231 % for the path, use the raw path with the query string and fragment
232 % removed, but URL quoting left intact
233 RawUri = MochiReq:get(raw_path),
234 {"/" ++ Path, _, _} = mochiweb_util:urlsplit_path(RawUri),
235
236 Headers = MochiReq:get(headers),
237
238 % get requested path
239 RequestedPath = case MochiReq:get_header_value("x-couchdb-vhost-path") of
240 undefined ->
241 case MochiReq:get_header_value("x-couchdb-requested-path") of
242 undefined -> RawUri;
243 R -> R
244 end;
245 P -> P
246 end,
247
248 HandlerKey =
249 case mochiweb_util:partition(Path, "/") of
250 {"", "", ""} ->
251 <<"/">>; % Special case the root url handler
252 {FirstPart, _, _} ->
253 list_to_binary(FirstPart)
254 end,
255 ?LOG_DEBUG("~p ~s ~p from ~p~nHeaders: ~p", [
256 MochiReq:get(method),
257 RawUri,
258 MochiReq:get(version),
259 MochiReq:get(peer),
260 mochiweb_headers:to_list(MochiReq:get(headers))
261 ]),
262
263 Method1 =
264 case MochiReq:get(method) of
265 % already an atom
266 Meth when is_atom(Meth) -> Meth;
267
268 % Non standard HTTP verbs aren't atoms (COPY, MOVE etc) so convert when
269 % possible (if any module references the atom, then it's existing).
270 Meth -> couch_util:to_existing_atom(Meth)
271 end,
272 increment_method_stats(Method1),
273
274 % allow broken HTTP clients to fake a full method vocabulary with an X-HTTP-METHOD-OVERRIDE header
275 MethodOverride = MochiReq:get_primary_header_value("X-HTTP-Method-Override"),
276 Method2 = case lists:member(MethodOverride, ["GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "COPY"]) of
277 true ->
278 ?LOG_INFO("MethodOverride: ~s (real method was ~s)", [MethodOverride, Method1]),
279 case Method1 of
280 'POST' -> couch_util:to_existing_atom(MethodOverride);
281 _ ->
282 % Ignore X-HTTP-Method-Override when the original verb isn't POST.
283 % I'd like to send a 406 error to the client, but that'd require a nasty refactor.
284 % throw({not_acceptable, <<"X-HTTP-Method-Override may only be used with POST requests.">>})
285 Method1
286 end;
287 _ -> Method1
288 end,
289
290 % alias HEAD to GET as mochiweb takes care of stripping the body
291 Method = case Method2 of
292 'HEAD' -> 'GET';
293 Other -> Other
294 end,
295
296 HttpReq = #httpd{
297 mochi_req = MochiReq,
298 peer = MochiReq:get(peer),
299 method = Method,
300 requested_path_parts =
301 [?l2b(unquote(Part)) || Part <- string:tokens(RequestedPath, "/")],
302 path_parts = [?l2b(unquote(Part)) || Part <- string:tokens(Path, "/")],
303 db_url_handlers = DbUrlHandlers,
304 design_url_handlers = DesignUrlHandlers,
305 default_fun = DefaultFun,
306 url_handlers = UrlHandlers,
307 user_ctx = erlang:erase(pre_rewrite_user_ctx)
308 },
309
310 HandlerFun = couch_util:dict_find(HandlerKey, UrlHandlers, DefaultFun),
311 {ok, AuthHandlers} = application:get_env(couch, auth_handlers),
312
313 {ok, Resp} =
314 try
315 case authenticate_request(HttpReq, AuthHandlers) of
316 #httpd{} = Req ->
317 HandlerFun(Req);
318 Response ->
319 Response
320 end
321 catch
322 throw:{http_head_abort, Resp0} ->
323 {ok, Resp0};
324 throw:{invalid_json, S} ->
325 ?LOG_ERROR("attempted upload of invalid JSON (set log_level to debug to log it)", []),
326 ?LOG_DEBUG("Invalid JSON: ~p",[S]),
327 send_error(HttpReq, {bad_request, invalid_json});
328 throw:unacceptable_encoding ->
329 ?LOG_ERROR("unsupported encoding method for the response", []),
330 send_error(HttpReq, {not_acceptable, "unsupported encoding"});
331 throw:bad_accept_encoding_value ->
332 ?LOG_ERROR("received invalid Accept-Encoding header", []),
333 send_error(HttpReq, bad_request);
334 exit:normal ->
335 exit(normal);
336 exit:snappy_nif_not_loaded ->
337 ErrorReason = "To access the database or view index, Apache CouchDB"
338 " must be built with Erlang OTP R13B04 or higher.",
339 ?LOG_ERROR("~s", [ErrorReason]),
340 send_error(HttpReq, {bad_otp_release, ErrorReason});
341 throw:Error ->
342 Stack = erlang:get_stacktrace(),
343 ?LOG_DEBUG("Minor error in HTTP request: ~p",[Error]),
344 ?LOG_DEBUG("Stacktrace: ~p",[Stack]),
345 send_error(HttpReq, Error);
346 error:badarg ->
347 Stack = erlang:get_stacktrace(),
348 ?LOG_ERROR("Badarg error in HTTP request",[]),
349 ?LOG_INFO("Stacktrace: ~p",[Stack]),
350 send_error(HttpReq, badarg);
351 error:function_clause ->
352 Stack = erlang:get_stacktrace(),
353 ?LOG_ERROR("function_clause error in HTTP request",[]),
354 ?LOG_INFO("Stacktrace: ~p",[Stack]),
355 send_error(HttpReq, function_clause);
356 Tag:Error ->
357 Stack = erlang:get_stacktrace(),
358 ?LOG_ERROR("Uncaught error in HTTP request: ~p",[{Tag, Error}]),
359 ?LOG_INFO("Stacktrace: ~p",[Stack]),
360 send_error(HttpReq, Error)
361 end,
362 RequestTime = round(timer:now_diff(now(), Begin)/1000),
363 couch_stats_collector:record({couchdb, request_time}, RequestTime),
364 couch_stats_collector:increment({httpd, requests}),
365 {ok, Resp}.
366
367% Try authentication handlers in order until one sets a user_ctx
368% the auth funs also have the option of returning a response
369% move this to couch_httpd_auth?
370authenticate_request(#httpd{user_ctx=#user_ctx{}} = Req, _AuthHandlers) ->
371 Req;
372authenticate_request(#httpd{} = Req, []) ->
373 case couch_config:get("couch_httpd_auth", "require_valid_user", "false") of
374 "true" ->
375 throw({unauthorized, <<"Authentication required.">>});
376 "false" ->
377 Req#httpd{user_ctx=#user_ctx{}}
378 end;
379authenticate_request(#httpd{} = Req, [{AuthFun, AuthSrc} | RestAuthHandlers]) ->
380 R = case AuthFun(Req) of
381 #httpd{user_ctx=#user_ctx{}=UserCtx}=Req2 ->
382 Req2#httpd{user_ctx=UserCtx#user_ctx{handler=AuthSrc}};
383 Else -> Else
384 end,
385 authenticate_request(R, RestAuthHandlers);
386authenticate_request(Response, _AuthSrcs) ->
387 Response.
388
389increment_method_stats(Method) ->
390 couch_stats_collector:increment({httpd_request_methods, Method}).
391
392validate_referer(Req) ->
393 Host = host_for_request(Req),
394 Referer = header_value(Req, "Referer", fail),
395 case Referer of
396 fail ->
397 throw({bad_request, <<"Referer header required.">>});
398 Referer ->
399 {_,RefererHost,_,_,_} = mochiweb_util:urlsplit(Referer),
400 if
401 RefererHost =:= Host -> ok;
402 true -> throw({bad_request, <<"Referer header must match host.">>})
403 end
404 end.
405
406validate_ctype(Req, Ctype) ->
407 case header_value(Req, "Content-Type") of
408 undefined ->
409 throw({bad_ctype, "Content-Type must be "++Ctype});
410 ReqCtype ->
411 case string:tokens(ReqCtype, ";") of
412 [Ctype] -> ok;
413 [Ctype, _Rest] -> ok;
414 _Else ->
415 throw({bad_ctype, "Content-Type must be "++Ctype})
416 end
417 end.
418
419% Utilities
420
421partition(Path) ->
422 mochiweb_util:partition(Path, "/").
423
424header_value(#httpd{mochi_req=MochiReq}, Key) ->
425 MochiReq:get_header_value(Key).
426
427header_value(#httpd{mochi_req=MochiReq}, Key, Default) ->
428 case MochiReq:get_header_value(Key) of
429 undefined -> Default;
430 Value -> Value
431 end.
432
433primary_header_value(#httpd{mochi_req=MochiReq}, Key) ->
434 MochiReq:get_primary_header_value(Key).
435
436accepted_encodings(#httpd{mochi_req=MochiReq}) ->
437 case MochiReq:accepted_encodings(["gzip", "identity"]) of
438 bad_accept_encoding_value ->
439 throw(bad_accept_encoding_value);
440 [] ->
441 throw(unacceptable_encoding);
442 EncList ->
443 EncList
444 end.
445
446serve_file(Req, RelativePath, DocumentRoot) ->
447 serve_file(Req, RelativePath, DocumentRoot, []).
448
449serve_file(#httpd{mochi_req=MochiReq}=Req, RelativePath, DocumentRoot, ExtraHeaders) ->
450 log_request(Req, 200),
451 {ok, MochiReq:serve_file(RelativePath, DocumentRoot,
452 server_header() ++ couch_httpd_auth:cookie_auth_header(Req, []) ++ ExtraHeaders)}.
453
454qs_value(Req, Key) ->
455 qs_value(Req, Key, undefined).
456
457qs_value(Req, Key, Default) ->
458 couch_util:get_value(Key, qs(Req), Default).
459
460qs_json_value(Req, Key, Default) ->
461 case qs_value(Req, Key, Default) of
462 Default ->
463 Default;
464 Result ->
465 ?JSON_DECODE(Result)
466 end.
467
468qs(#httpd{mochi_req=MochiReq}) ->
469 MochiReq:parse_qs().
470
471path(#httpd{mochi_req=MochiReq}) ->
472 MochiReq:get(path).
473
474host_for_request(#httpd{mochi_req=MochiReq}) ->
475 XHost = couch_config:get("httpd", "x_forwarded_host", "X-Forwarded-Host"),
476 case MochiReq:get_header_value(XHost) of
477 undefined ->
478 case MochiReq:get_header_value("Host") of
479 undefined ->
480 {ok, {Address, Port}} = inet:sockname(MochiReq:get(socket)),
481 inet_parse:ntoa(Address) ++ ":" ++ integer_to_list(Port);
482 Value1 ->
483 Value1
484 end;
485 Value -> Value
486 end.
487
488absolute_uri(#httpd{mochi_req=MochiReq}=Req, Path) ->
489 Host = host_for_request(Req),
490 XSsl = couch_config:get("httpd", "x_forwarded_ssl", "X-Forwarded-Ssl"),
491 Scheme = case MochiReq:get_header_value(XSsl) of
492 "on" -> "https";
493 _ ->
494 XProto = couch_config:get("httpd", "x_forwarded_proto", "X-Forwarded-Proto"),
495 case MochiReq:get_header_value(XProto) of
496 %% Restrict to "https" and "http" schemes only
497 "https" -> "https";
498 _ -> case MochiReq:get(scheme) of
499 https -> "https";
500 http -> "http"
501 end
502 end
503 end,
504 Scheme ++ "://" ++ Host ++ Path.
505
506unquote(UrlEncodedString) ->
507 mochiweb_util:unquote(UrlEncodedString).
508
509quote(UrlDecodedString) ->
510 mochiweb_util:quote_plus(UrlDecodedString).
511
512parse_form(#httpd{mochi_req=MochiReq}) ->
513 mochiweb_multipart:parse_form(MochiReq).
514
515recv(#httpd{mochi_req=MochiReq}, Len) ->
516 MochiReq:recv(Len).
517
518recv_chunked(#httpd{mochi_req=MochiReq}, MaxChunkSize, ChunkFun, InitState) ->
519 % Fun is called once with each chunk
520 % Fun({Length, Binary}, State)
521 % called with Length == 0 on the last time.
522 MochiReq:stream_body(MaxChunkSize, ChunkFun, InitState).
523
524body_length(Req) ->
525 case header_value(Req, "Transfer-Encoding") of
526 undefined ->
527 case header_value(Req, "Content-Length") of
528 undefined -> undefined;
529 Length -> list_to_integer(Length)
530 end;
531 "chunked" -> chunked;
532 Unknown -> {unknown_transfer_encoding, Unknown}
533 end.
534
535body(#httpd{mochi_req=MochiReq, req_body=undefined} = Req) ->
536 case body_length(Req) of
537 undefined ->
538 MaxSize = list_to_integer(
539 couch_config:get("couchdb", "max_document_size", "4294967296")),
540 MochiReq:recv_body(MaxSize);
541 chunked ->
542 ChunkFun = fun({0, _Footers}, Acc) ->
543 lists:reverse(Acc);
544 ({_Len, Chunk}, Acc) ->
545 [Chunk | Acc]
546 end,
547 recv_chunked(Req, 8192, ChunkFun, []);
548 Len ->
549 MochiReq:recv_body(Len)
550 end;
551body(#httpd{req_body=ReqBody}) ->
552 ReqBody.
553
554json_body(Httpd) ->
555 ?JSON_DECODE(body(Httpd)).
556
557json_body_obj(Httpd) ->
558 case json_body(Httpd) of
559 {Props} -> {Props};
560 _Else ->
561 throw({bad_request, "Request body must be a JSON object"})
562 end.
563
564
565
566doc_etag(#doc{revs={Start, [DiskRev|_]}}) ->
567 "\"" ++ ?b2l(couch_doc:rev_to_str({Start, DiskRev})) ++ "\"".
568
569make_etag(Term) ->
570 <<SigInt:128/integer>> = couch_util:md5(term_to_binary(Term)),
571 iolist_to_binary([$", io_lib:format("~.36B", [SigInt]), $"]).
572
573etag_match(Req, CurrentEtag) when is_binary(CurrentEtag) ->
574 etag_match(Req, binary_to_list(CurrentEtag));
575
576etag_match(Req, CurrentEtag) ->
577 EtagsToMatch = string:tokens(
578 header_value(Req, "If-None-Match", ""), ", "),
579 lists:member(CurrentEtag, EtagsToMatch).
580
581etag_respond(Req, CurrentEtag, RespFun) ->
582 case etag_match(Req, CurrentEtag) of
583 true ->
584 % the client has this in their cache.
585 send_response(Req, 304, [{"ETag", CurrentEtag}], <<>>);
586 false ->
587 % Run the function.
588 RespFun()
589 end.
590
591verify_is_server_admin(#httpd{user_ctx=UserCtx}) ->
592 verify_is_server_admin(UserCtx);
593verify_is_server_admin(#user_ctx{roles=Roles}) ->
594 case lists:member(<<"_admin">>, Roles) of
595 true -> ok;
596 false -> throw({unauthorized, <<"You are not a server admin.">>})
597 end.
598
599log_request(#httpd{mochi_req=MochiReq,peer=Peer}, Code) ->
600 ?LOG_INFO("~s - - ~s ~s ~B", [
601 Peer,
602 MochiReq:get(method),
603 MochiReq:get(raw_path),
604 Code
605 ]).
606
607
608start_response_length(#httpd{mochi_req=MochiReq}=Req, Code, Headers, Length) ->
609 log_request(Req, Code),
610 couch_stats_collector:increment({httpd_status_codes, Code}),
611 Resp = MochiReq:start_response_length({Code, Headers ++ server_header() ++ couch_httpd_auth:cookie_auth_header(Req, Headers), Length}),
612 case MochiReq:get(method) of
613 'HEAD' -> throw({http_head_abort, Resp});
614 _ -> ok
615 end,
616 {ok, Resp}.
617
618start_response(#httpd{mochi_req=MochiReq}=Req, Code, Headers) ->
619 log_request(Req, Code),
620 couch_stats_collector:increment({httpd_status_cdes, Code}),
621 CookieHeader = couch_httpd_auth:cookie_auth_header(Req, Headers),
622 Headers2 = Headers ++ server_header() ++ CookieHeader,
623 Resp = MochiReq:start_response({Code, Headers2}),
624 case MochiReq:get(method) of
625 'HEAD' -> throw({http_head_abort, Resp});
626 _ -> ok
627 end,
628 {ok, Resp}.
629
630send(Resp, Data) ->
631 Resp:send(Data),
632 {ok, Resp}.
633
634no_resp_conn_header([]) ->
635 true;
636no_resp_conn_header([{Hdr, _}|Rest]) ->
637 case string:to_lower(Hdr) of
638 "connection" -> false;
639 _ -> no_resp_conn_header(Rest)
640 end.
641
642http_1_0_keep_alive(Req, Headers) ->
643 KeepOpen = Req:should_close() == false,
644 IsHttp10 = Req:get(version) == {1, 0},
645 NoRespHeader = no_resp_conn_header(Headers),
646 case KeepOpen andalso IsHttp10 andalso NoRespHeader of
647 true -> [{"Connection", "Keep-Alive"} | Headers];
648 false -> Headers
649 end.
650
651start_chunked_response(#httpd{mochi_req=MochiReq}=Req, Code, Headers) ->
652 log_request(Req, Code),
653 couch_stats_collector:increment({httpd_status_codes, Code}),
654 Headers2 = http_1_0_keep_alive(MochiReq, Headers),
655 Resp = MochiReq:respond({Code, Headers2 ++ server_header() ++ couch_httpd_auth:cookie_auth_header(Req, Headers2), chunked}),
656 case MochiReq:get(method) of
657 'HEAD' -> throw({http_head_abort, Resp});
658 _ -> ok
659 end,
660 {ok, Resp}.
661
662send_chunk(Resp, Data) ->
663 case iolist_size(Data) of
664 0 -> ok; % do nothing
665 _ -> Resp:write_chunk(Data)
666 end,
667 {ok, Resp}.
668
669last_chunk(Resp) ->
670 Resp:write_chunk([]),
671 {ok, Resp}.
672
673send_response(#httpd{mochi_req=MochiReq}=Req, Code, Headers, Body) ->
674 log_request(Req, Code),
675 couch_stats_collector:increment({httpd_status_codes, Code}),
676 Headers2 = http_1_0_keep_alive(MochiReq, Headers),
677 if Code >= 400 ->
678 ?LOG_DEBUG("httpd ~p error response:~n ~s", [Code, Body]);
679 true -> ok
680 end,
681 {ok, MochiReq:respond({Code, Headers2 ++ server_header() ++ couch_httpd_auth:cookie_auth_header(Req, Headers2), Body})}.
682
683send_method_not_allowed(Req, Methods) ->
684 send_error(Req, 405, [{"Allow", Methods}], <<"method_not_allowed">>, ?l2b("Only " ++ Methods ++ " allowed")).
685
686send_json(Req, Value) ->
687 send_json(Req, 200, Value).
688
689send_json(Req, Code, Value) ->
690 send_json(Req, Code, [], Value).
691
692send_json(Req, Code, Headers, Value) ->
693 initialize_jsonp(Req),
694 DefaultHeaders = [
695 {"Content-Type", negotiate_content_type(Req)},
696 {"Cache-Control", "must-revalidate"}
697 ],
698 Body = [start_jsonp(), ?JSON_ENCODE(Value), end_jsonp(), $\n],
699 send_response(Req, Code, DefaultHeaders ++ Headers, Body).
700
701start_json_response(Req, Code) ->
702 start_json_response(Req, Code, []).
703
704start_json_response(Req, Code, Headers) ->
705 initialize_jsonp(Req),
706 DefaultHeaders = [
707 {"Content-Type", negotiate_content_type(Req)},
708 {"Cache-Control", "must-revalidate"}
709 ],
710 {ok, Resp} = start_chunked_response(Req, Code, DefaultHeaders ++ Headers),
711 case start_jsonp() of
712 [] -> ok;
713 Start -> send_chunk(Resp, Start)
714 end,
715 {ok, Resp}.
716
717end_json_response(Resp) ->
718 send_chunk(Resp, end_jsonp() ++ [$\n]),
719 last_chunk(Resp).
720
721initialize_jsonp(Req) ->
722 case get(jsonp) of
723 undefined -> put(jsonp, qs_value(Req, "callback", no_jsonp));
724 _ -> ok
725 end,
726 case get(jsonp) of
727 no_jsonp -> [];
728 [] -> [];
729 CallBack ->
730 try
731 % make sure jsonp is configured on (default off)
732 case couch_config:get("httpd", "allow_jsonp", "false") of
733 "true" ->
734 validate_callback(CallBack);
735 _Else ->
736 put(jsonp, no_jsonp)
737 end
738 catch
739 Error ->
740 put(jsonp, no_jsonp),
741 throw(Error)
742 end
743 end.
744
745start_jsonp() ->
746 case get(jsonp) of
747 no_jsonp -> [];
748 [] -> [];
749 CallBack -> CallBack ++ "("
750 end.
751
752end_jsonp() ->
753 case erlang:erase(jsonp) of
754 no_jsonp -> [];
755 [] -> [];
756 _ -> ");"
757 end.
758
759validate_callback(CallBack) when is_binary(CallBack) ->
760 validate_callback(binary_to_list(CallBack));
761validate_callback([]) ->
762 ok;
763validate_callback([Char | Rest]) ->
764 case Char of
765 _ when Char >= $a andalso Char =< $z -> ok;
766 _ when Char >= $A andalso Char =< $Z -> ok;
767 _ when Char >= $0 andalso Char =< $9 -> ok;
768 _ when Char == $. -> ok;
769 _ when Char == $_ -> ok;
770 _ when Char == $[ -> ok;
771 _ when Char == $] -> ok;
772 _ ->
773 throw({bad_request, invalid_callback})
774 end,
775 validate_callback(Rest).
776
777
778error_info({Error, Reason}) when is_list(Reason) ->
779 error_info({Error, ?l2b(Reason)});
780error_info(bad_request) ->
781 {400, <<"bad_request">>, <<>>};
782error_info({bad_request, Reason}) ->
783 {400, <<"bad_request">>, Reason};
784error_info({query_parse_error, Reason}) ->
785 {400, <<"query_parse_error">>, Reason};
786% Prior art for md5 mismatch resulting in a 400 is from AWS S3
787error_info(md5_mismatch) ->
788 {400, <<"content_md5_mismatch">>, <<"Possible message corruption.">>};
789error_info(not_found) ->
790 {404, <<"not_found">>, <<"missing">>};
791error_info({not_found, Reason}) ->
792 {404, <<"not_found">>, Reason};
793error_info({not_acceptable, Reason}) ->
794 {406, <<"not_acceptable">>, Reason};
795error_info(conflict) ->
796 {409, <<"conflict">>, <<"Document update conflict.">>};
797error_info({forbidden, Msg}) ->
798 {403, <<"forbidden">>, Msg};
799error_info({unauthorized, Msg}) ->
800 {401, <<"unauthorized">>, Msg};
801error_info(file_exists) ->
802 {412, <<"file_exists">>, <<"The database could not be "
803 "created, the file already exists.">>};
804error_info({bad_ctype, Reason}) ->
805 {415, <<"bad_content_type">>, Reason};
806error_info(requested_range_not_satisfiable) ->
807 {416, <<"requested_range_not_satisfiable">>, <<"Requested range not satisfiable">>};
808error_info({error, illegal_database_name}) ->
809 {400, <<"illegal_database_name">>, <<"Only lowercase characters (a-z), "
810 "digits (0-9), and any of the characters _, $, (, ), +, -, and / "
811 "are allowed. Must begin with a letter.">>};
812error_info({missing_stub, Reason}) ->
813 {412, <<"missing_stub">>, Reason};
814error_info({Error, Reason}) ->
815 ?LOG_ERROR("Uncaught server error: ~p", [{Error, Reason}]),
816 {500, couch_util:to_binary(Error), couch_util:to_binary(Reason)};
817error_info(Error) ->
818 ?LOG_ERROR("Uncaught server error: ~p", [Error]),
819 {500, <<"unknown_error">>, couch_util:to_binary(Error)}.
820
821error_headers(#httpd{mochi_req=MochiReq}=Req, Code, ErrorStr, ReasonStr) ->
822 if Code == 401 ->
823 % this is where the basic auth popup is triggered
824 case MochiReq:get_header_value("X-CouchDB-WWW-Authenticate") of
825 undefined ->
826 case couch_config:get("httpd", "WWW-Authenticate", nil) of
827 nil ->
828 % If the client is a browser and the basic auth popup isn't turned on
829 % redirect to the session page.
830 case ErrorStr of
831 <<"unauthorized">> ->
832 case couch_config:get("couch_httpd_auth", "authentication_redirect", nil) of
833 nil -> {Code, []};
834 AuthRedirect ->
835 case couch_config:get("couch_httpd_auth", "require_valid_user", "false") of
836 "true" ->
837 % send the browser popup header no matter what if we are require_valid_user
838 {Code, [{"WWW-Authenticate", "Basic realm=\"server\""}]};
839 _False ->
840 case MochiReq:accepts_content_type("application/json") of
841 true ->
842 {Code, []};
843 false ->
844 case MochiReq:accepts_content_type("text/html") of
845 true ->
846 % Redirect to the path the user requested, not
847 % the one that is used internally.
848 UrlReturnRaw = case MochiReq:get_header_value("x-couchdb-vhost-path") of
849 undefined ->
850 MochiReq:get(path);
851 VHostPath ->
852 VHostPath
853 end,
854 RedirectLocation = lists:flatten([
855 AuthRedirect,
856 "?return=", couch_util:url_encode(UrlReturnRaw),
857 "&reason=", couch_util:url_encode(ReasonStr)
858 ]),
859 {302, [{"Location", absolute_uri(Req, RedirectLocation)}]};
860 false ->
861 {Code, []}
862 end
863 end
864 end
865 end;
866 _Else ->
867 {Code, []}
868 end;
869 Type ->
870 {Code, [{"WWW-Authenticate", Type}]}
871 end;
872 Type ->
873 {Code, [{"WWW-Authenticate", Type}]}
874 end;
875 true ->
876 {Code, []}
877 end.
878
879send_error(_Req, {already_sent, Resp, _Error}) ->
880 {ok, Resp};
881
882send_error(Req, Error) ->
883 {Code, ErrorStr, ReasonStr} = error_info(Error),
884 {Code1, Headers} = error_headers(Req, Code, ErrorStr, ReasonStr),
885 send_error(Req, Code1, Headers, ErrorStr, ReasonStr).
886
887send_error(Req, Code, ErrorStr, ReasonStr) ->
888 send_error(Req, Code, [], ErrorStr, ReasonStr).
889
890send_error(Req, Code, Headers, ErrorStr, ReasonStr) ->
891 send_json(Req, Code, Headers,
892 {[{<<"error">>, ErrorStr},
893 {<<"reason">>, ReasonStr}]}).
894
895% give the option for list functions to output html or other raw errors
896send_chunked_error(Resp, {_Error, {[{<<"body">>, Reason}]}}) ->
897 send_chunk(Resp, Reason),
898 last_chunk(Resp);
899
900send_chunked_error(Resp, Error) ->
901 {Code, ErrorStr, ReasonStr} = error_info(Error),
902 JsonError = {[{<<"code">>, Code},
903 {<<"error">>, ErrorStr},
904 {<<"reason">>, ReasonStr}]},
905 send_chunk(Resp, ?l2b([$\n,?JSON_ENCODE(JsonError),$\n])),
906 last_chunk(Resp).
907
908send_redirect(Req, Path) ->
909 send_response(Req, 301, [{"Location", absolute_uri(Req, Path)}], <<>>).
910
911negotiate_content_type(Req) ->
912 case get(jsonp) of
913 no_jsonp -> negotiate_content_type1(Req);
914 [] -> negotiate_content_type1(Req);
915 _Callback -> "text/javascript"
916 end.
917
918negotiate_content_type1(#httpd{mochi_req=MochiReq}) ->
919 %% Determine the appropriate Content-Type header for a JSON response
920 %% depending on the Accept header in the request. A request that explicitly
921 %% lists the correct JSON MIME type will get that type, otherwise the
922 %% response will have the generic MIME type "text/plain"
923 AcceptedTypes = case MochiReq:get_header_value("Accept") of
924 undefined -> [];
925 AcceptHeader -> string:tokens(AcceptHeader, ", ")
926 end,
927 case lists:member("application/json", AcceptedTypes) of
928 true -> "application/json";
929 false -> "text/plain; charset=utf-8"
930 end.
931
932server_header() ->
933 [{"Server", "CouchDB/" ++ couch_server:get_version() ++
934 " (Erlang OTP/" ++ erlang:system_info(otp_release) ++ ")"}].
935
936
937-record(mp, {boundary, buffer, data_fun, callback}).
938
939
940parse_multipart_request(ContentType, DataFun, Callback) ->
941 Boundary0 = iolist_to_binary(get_boundary(ContentType)),
942 Boundary = <<"\r\n--", Boundary0/binary>>,
943 Mp = #mp{boundary= Boundary,
944 buffer= <<>>,
945 data_fun=DataFun,
946 callback=Callback},
947 {Mp2, _NilCallback} = read_until(Mp, <<"--", Boundary0/binary>>,
948 fun nil_callback/1),
949 #mp{buffer=Buffer, data_fun=DataFun2, callback=Callback2} =
950 parse_part_header(Mp2),
951 {Buffer, DataFun2, Callback2}.
952
953nil_callback(_Data)->
954 fun nil_callback/1.
955
956get_boundary({"multipart/" ++ _, Opts}) ->
957 case couch_util:get_value("boundary", Opts) of
958 S when is_list(S) ->
959 S
960 end;
961get_boundary(ContentType) ->
962 {"multipart/" ++ _ , Opts} = mochiweb_util:parse_header(ContentType),
963 get_boundary({"multipart/", Opts}).
964
965
966
967split_header(<<>>) ->
968 [];
969split_header(Line) ->
970 {Name, [$: | Value]} = lists:splitwith(fun (C) -> C =/= $: end,
971 binary_to_list(Line)),
972 [{string:to_lower(string:strip(Name)),
973 mochiweb_util:parse_header(Value)}].
974
975read_until(#mp{data_fun=DataFun, buffer=Buffer}=Mp, Pattern, Callback) ->
976 case find_in_binary(Pattern, Buffer) of
977 not_found ->
978 Callback2 = Callback(Buffer),
979 {Buffer2, DataFun2} = DataFun(),
980 Buffer3 = iolist_to_binary(Buffer2),
981 read_until(Mp#mp{data_fun=DataFun2,buffer=Buffer3}, Pattern, Callback2);
982 {partial, 0} ->
983 {NewData, DataFun2} = DataFun(),
984 read_until(Mp#mp{data_fun=DataFun2,
985 buffer= iolist_to_binary([Buffer,NewData])},
986 Pattern, Callback);
987 {partial, Skip} ->
988 <<DataChunk:Skip/binary, Rest/binary>> = Buffer,
989 Callback2 = Callback(DataChunk),
990 {NewData, DataFun2} = DataFun(),
991 read_until(Mp#mp{data_fun=DataFun2,
992 buffer= iolist_to_binary([Rest | NewData])},
993 Pattern, Callback2);
994 {exact, 0} ->
995 PatternLen = size(Pattern),
996 <<_:PatternLen/binary, Rest/binary>> = Buffer,
997 {Mp#mp{buffer= Rest}, Callback};
998 {exact, Skip} ->
999 PatternLen = size(Pattern),
1000 <<DataChunk:Skip/binary, _:PatternLen/binary, Rest/binary>> = Buffer,
1001 Callback2 = Callback(DataChunk),
1002 {Mp#mp{buffer= Rest}, Callback2}
1003 end.
1004
1005
1006parse_part_header(#mp{callback=UserCallBack}=Mp) ->
1007 {Mp2, AccCallback} = read_until(Mp, <<"\r\n\r\n">>,
1008 fun(Next) -> acc_callback(Next, []) end),
1009 HeaderData = AccCallback(get_data),
1010
1011 Headers =
1012 lists:foldl(fun(Line, Acc) ->
1013 split_header(Line) ++ Acc
1014 end, [], re:split(HeaderData,<<"\r\n">>, [])),
1015 NextCallback = UserCallBack({headers, Headers}),
1016 parse_part_body(Mp2#mp{callback=NextCallback}).
1017
1018parse_part_body(#mp{boundary=Prefix, callback=Callback}=Mp) ->
1019 {Mp2, WrappedCallback} = read_until(Mp, Prefix,
1020 fun(Data) -> body_callback_wrapper(Data, Callback) end),
1021 Callback2 = WrappedCallback(get_callback),
1022 Callback3 = Callback2(body_end),
1023 case check_for_last(Mp2#mp{callback=Callback3}) of
1024 {last, #mp{callback=Callback3}=Mp3} ->
1025 Mp3#mp{callback=Callback3(eof)};
1026 {more, Mp3} ->
1027 parse_part_header(Mp3)
1028 end.
1029
1030acc_callback(get_data, Acc)->
1031 iolist_to_binary(lists:reverse(Acc));
1032acc_callback(Data, Acc)->
1033 fun(Next) -> acc_callback(Next, [Data | Acc]) end.
1034
1035body_callback_wrapper(get_callback, Callback) ->
1036 Callback;
1037body_callback_wrapper(Data, Callback) ->
1038 Callback2 = Callback({body, Data}),
1039 fun(Next) -> body_callback_wrapper(Next, Callback2) end.
1040
1041
1042check_for_last(#mp{buffer=Buffer, data_fun=DataFun}=Mp) ->
1043 case Buffer of
1044 <<"--",_/binary>> -> {last, Mp};
1045 <<_, _, _/binary>> -> {more, Mp};
1046 _ -> % not long enough
1047 {Data, DataFun2} = DataFun(),
1048 check_for_last(Mp#mp{buffer= <<Buffer/binary, Data/binary>>,
1049 data_fun = DataFun2})
1050 end.
1051
1052find_in_binary(B, Data) when size(B) > 0 ->
1053 case size(Data) - size(B) of
1054 Last when Last < 0 ->
1055 partial_find(B, Data, 0, size(Data));
1056 Last ->
1057 find_in_binary(B, size(B), Data, 0, Last)
1058 end.
1059
1060find_in_binary(B, BS, D, N, Last) when N =< Last->
1061 case D of
1062 <<_:N/binary, B:BS/binary, _/binary>> ->
1063 {exact, N};
1064 _ ->
1065 find_in_binary(B, BS, D, 1 + N, Last)
1066 end;
1067find_in_binary(B, BS, D, N, Last) when N =:= 1 + Last ->
1068 partial_find(B, D, N, BS - 1).
1069
1070partial_find(_B, _D, _N, 0) ->
1071 not_found;
1072partial_find(B, D, N, K) ->
1073 <<B1:K/binary, _/binary>> = B,
1074 case D of
1075 <<_Skip:N/binary, B1/binary>> ->
1076 {partial, N};
1077 _ ->
1078 partial_find(B, D, 1 + N, K - 1)
1079 end.
1080
1081
10820
=== removed directory '.pc/logrotate_as_couchdb.patch'
=== removed directory '.pc/logrotate_as_couchdb.patch/etc'
=== removed directory '.pc/logrotate_as_couchdb.patch/etc/logrotate.d'
=== removed file '.pc/logrotate_as_couchdb.patch/etc/logrotate.d/couchdb.tpl.in'
--- .pc/logrotate_as_couchdb.patch/etc/logrotate.d/couchdb.tpl.in 2012-11-18 12:24:24 +0000
+++ .pc/logrotate_as_couchdb.patch/etc/logrotate.d/couchdb.tpl.in 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
1%localstatelogdir%/*.log {
2 weekly
3 rotate 10
4 copytruncate
5 delaycompress
6 compress
7 notifempty
8 missingok
9}
100
=== removed directory '.pc/wait_for_couchdb_stop.patch'
=== removed directory '.pc/wait_for_couchdb_stop.patch/etc'
=== removed directory '.pc/wait_for_couchdb_stop.patch/etc/init'
=== removed file '.pc/wait_for_couchdb_stop.patch/etc/init/couchdb.tpl.in'
--- .pc/wait_for_couchdb_stop.patch/etc/init/couchdb.tpl.in 2012-11-18 12:24:24 +0000
+++ .pc/wait_for_couchdb_stop.patch/etc/init/couchdb.tpl.in 1970-01-01 00:00:00 +0000
@@ -1,157 +0,0 @@
1#!/bin/sh -e
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15### BEGIN INIT INFO
16# Provides: couchdb
17# Required-Start: $local_fs $remote_fs
18# Required-Stop: $local_fs $remote_fs
19# Default-Start: 2 3 4 5
20# Default-Stop: 0 1 6
21# Short-Description: Apache CouchDB init script
22# Description: Apache CouchDB init script for the database server.
23### END INIT INFO
24
25SCRIPT_OK=0
26SCRIPT_ERROR=1
27
28DESCRIPTION="database server"
29NAME=couchdb
30SCRIPT_NAME=`basename $0`
31COUCHDB=%bindir%/%couchdb_command_name%
32CONFIGURATION_FILE=%sysconfdir%/default/couchdb
33RUN_DIR=%localstaterundir%
34LSB_LIBRARY=/lib/lsb/init-functions
35
36if test ! -x $COUCHDB; then
37 exit $SCRIPT_ERROR
38fi
39
40if test -r $CONFIGURATION_FILE; then
41 . $CONFIGURATION_FILE
42fi
43
44log_daemon_msg () {
45 # Dummy function to be replaced by LSB library.
46
47 echo $@
48}
49
50log_end_msg () {
51 # Dummy function to be replaced by LSB library.
52
53 if test "$1" != "0"; then
54 echo "Error with $DESCRIPTION: $NAME"
55 fi
56 return $1
57}
58
59if test -r $LSB_LIBRARY; then
60 . $LSB_LIBRARY
61fi
62
63run_command () {
64 command="$1"
65 if test -n "$COUCHDB_OPTIONS"; then
66 command="$command $COUCHDB_OPTIONS"
67 fi
68 if test -n "$COUCHDB_USER"; then
69 if su $COUCHDB_USER -c "$command"; then
70 return $SCRIPT_OK
71 else
72 return $SCRIPT_ERROR
73 fi
74 else
75 if $command; then
76 return $SCRIPT_OK
77 else
78 return $SCRIPT_ERROR
79 fi
80 fi
81}
82
83start_couchdb () {
84 # Start Apache CouchDB as a background process.
85
86 test -e "$RUN_DIR" || \
87 install -m 755 -o "$COUCHDB_USER" -g "$COUCHDB_USER" -d "$RUN_DIR"
88 command="$COUCHDB -b"
89 if test -n "$COUCHDB_STDOUT_FILE"; then
90 command="$command -o $COUCHDB_STDOUT_FILE"
91 fi
92 if test -n "$COUCHDB_STDERR_FILE"; then
93 command="$command -e $COUCHDB_STDERR_FILE"
94 fi
95 if test -n "$COUCHDB_RESPAWN_TIMEOUT"; then
96 command="$command -r $COUCHDB_RESPAWN_TIMEOUT"
97 fi
98 run_command "$command" > /dev/null
99}
100
101stop_couchdb () {
102 # Stop the running Apache CouchDB process.
103
104 run_command "$COUCHDB -d" > /dev/null
105}
106
107display_status () {
108 # Display the status of the running Apache CouchDB process.
109
110 run_command "$COUCHDB -s"
111}
112
113parse_script_option_list () {
114 # Parse arguments passed to the script and take appropriate action.
115
116 case "$1" in
117 start)
118 log_daemon_msg "Starting $DESCRIPTION" $NAME
119 if start_couchdb; then
120 log_end_msg $SCRIPT_OK
121 else
122 log_end_msg $SCRIPT_ERROR
123 fi
124 ;;
125 stop)
126 log_daemon_msg "Stopping $DESCRIPTION" $NAME
127 if stop_couchdb; then
128 log_end_msg $SCRIPT_OK
129 else
130 log_end_msg $SCRIPT_ERROR
131 fi
132 ;;
133 restart|force-reload)
134 log_daemon_msg "Restarting $DESCRIPTION" $NAME
135 if stop_couchdb; then
136 if start_couchdb; then
137 log_end_msg $SCRIPT_OK
138 else
139 log_end_msg $SCRIPT_ERROR
140 fi
141 else
142 log_end_msg $SCRIPT_ERROR
143 fi
144 ;;
145 status)
146 display_status
147 ;;
148 *)
149 cat << EOF >&2
150Usage: $SCRIPT_NAME {start|stop|restart|force-reload|status}
151EOF
152 exit $SCRIPT_ERROR
153 ;;
154 esac
155}
156
157parse_script_option_list $@
1580
=== modified file 'AUTHORS'
--- AUTHORS 2012-07-30 22:49:59 +0000
+++ AUTHORS 2013-08-30 22:06:57 +0000
@@ -20,5 +20,11 @@
20 * Bob Dionne <bitdiddle@apache.org>20 * Bob Dionne <bitdiddle@apache.org>
21 * Dave Cottlehuber <dch@apache.org>21 * Dave Cottlehuber <dch@apache.org>
22 * Jason Smith <jhs@apache.org>22 * Jason Smith <jhs@apache.org>
23 * Joan Touzet <joant@ieee.org>
24 * Dale Harvey <dale@apache.org>
25 * Dirkjan Ochtman <djc@apache.org>
26 * Alexander Shorin <kxepal@apache.org>
27 * Garren Smith <garren@apache.org>
28 * Sue Lockwood <deathbear@apache.org>
2329
24For a list of other credits see the `THANKS` file.30For a list of other credits see the `THANKS` file.
2531
=== modified file 'BUGS'
--- BUGS 2009-04-14 16:32:45 +0000
+++ BUGS 2013-08-30 22:06:57 +0000
@@ -1,6 +1,8 @@
1Apache CouchDB BUGS1Apache CouchDB BUGS
2===================2===================
33
4Please see the [documentation][1] on how to report bugs with Apache CouchDB.4Visit our issue tracker:
55
6[1] http://couchdb.apache.org/community/issues.html6 https://issues.apache.org/jira/browse/CouchDB
7
8You can use this to report bugs, request features, or suggest enhancements.
79
=== removed file 'CHANGES'
--- CHANGES 2012-07-30 22:49:59 +0000
+++ CHANGES 1970-01-01 00:00:00 +0000
@@ -1,874 +0,0 @@
1Apache CouchDB CHANGES
2======================
3
4Version 1.2.0
5-------------
6
7Authentication:
8
9 * Fix use of OAuth with VHosts and URL rewriting.
10 * OAuth secrets can now be stored in the users system database
11 as an alternative to key value pairs in the .ini configuration.
12 By default this is disabled (secrets are stored in the .ini)
13 but can be enabled via the .ini configuration key `use_users_db`
14 in the `couch_httpd_oauth` section.
15 * Documents in the _users database are no longer publicly
16 readable.
17 * Confidential information in the _replication database is no
18 longer publicly readable.
19 * Password hashes are now calculated by CouchDB. Clients are no
20 longer required to do this manually.
21 * Cookies used for authentication can be made persistent by enabling
22 the .ini configuration key `allow_persistent_cookies' in the
23 `couch_httpd_auth` section.
24
25Build System:
26
27 * cURL is no longer required to build CouchDB as it is only
28 used by the command line JS test runner. If cURL is available
29 when building CouchJS you can enable the HTTP bindings by
30 passing -H on the command line.
31 * Temporarily made `make check` pass with R15B. A more thorough
32 fix is in the works (COUCHDB-1424).
33 * Fixed --with-js-include and --with-js-lib options.
34 * Added --with-js-lib-name option.
35
36HTTP Interface:
37
38 * Added a native JSON parser.
39 * The _active_tasks API now offers more granular fields. Each
40 task type is now able to expose different properties.
41 * Added built-in changes feed filter `_view`.
42 * Fixes to the `_changes` feed heartbeat option which caused
43 heartbeats to be missed when used with a filter. This caused
44 timeouts of continuous pull replications with a filter.
45 * Properly restart the SSL socket on configuration changes.
46
47Replicator:
48
49 * A new replicator implementation. It offers more performance and
50 configuration options.
51 * Passing non-string values to query_params is now a 400 bad
52 request. This is to reduce the surprise that all parameters
53 are converted to strings internally.
54 * Added optional field `since_seq` to replication objects/documents.
55 It allows to bootstrap a replication from a specific source sequence
56 number.
57 * Simpler replication cancellation. In addition to the current method,
58 replications can now be canceled by specifying the replication ID
59 instead of the original replication object/document.
60
61Storage System:
62
63 * Added optional database and view index file compression (using Google's
64 snappy or zlib's deflate). This feature is enabled by default, but it
65 can be disabled by adapting local.ini accordingly. The on-disk format
66 is upgraded on compaction and new DB/view creation to support this.
67 * Several performance improvements, most notably regarding database writes
68 and view indexing.
69 * Computation of the size of the latest MVCC snapshot data and all its
70 supporting metadata, both for database and view index files. This
71 information is exposed as the `data_size` attribute in the database and
72 view group information URIs.
73 * The size of the buffers used for database and view compaction is now
74 configurable.
75 * Added support for automatic database and view compaction. This feature
76 is disabled by default, but it can be enabled via the .ini configuration.
77 * Performance improvements for the built-in changes feed filters `_doc_ids`
78 and `_design'.
79
80View Server:
81
82 * Add CoffeeScript (http://coffeescript.org/) as a first class view server
83 language.
84 * Fixed old index file descriptor leaks after a view cleanup.
85 * The requested_path property keeps the pre-rewrite path even when no VHost
86 configuration is matched.
87 * Fixed incorrect reduce query results when using pagination parameters.
88 * Made icu_driver work with Erlang R15B and later.
89 * Avoid invalidating view indexes when running out of file descriptors.
90
91OAuth:
92
93 * Updated bundled erlang_oauth library to the latest version.
94
95Futon:
96
97 * The `Status` screen (active tasks) now displays two new task status
98 fields: `Started on` and `Updated on`.
99 * Futon remembers view code every time it is saved, allowing to save an
100 edit that amounts to a revert.
101
102Log System:
103
104 * Log correct stacktrace in all cases.
105 * Improvements to log messages for file-related errors.
106
107Version 1.1.1
108-------------
109
110* Support SpiderMonkey 1.8.5
111* Add configurable maximum to the number of bytes returned by _log.
112* Allow CommonJS modules to be an empty string.
113* Bump minimum Erlang version to R13B02.
114* Do not run deleted validate_doc_update functions.
115* ETags for views include current sequence if include_docs=true.
116* Fix bug where duplicates can appear in _changes feed.
117* Fix bug where update handlers break after conflict resolution.
118* Fix bug with _replicator where include "filter" could crash couch.
119* Fix crashes when compacting large views.
120* Fix file descriptor leak in _log
121* Fix missing revisions in _changes?style=all_docs.
122* Improve handling of compaction at max_dbs_open limit.
123* JSONP responses now send "text/javascript" for Content-Type.
124* Link to ICU 4.2 on Windows.
125* Permit forward slashes in path to update functions.
126* Reap couchjs processes that hit reduce_overflow error.
127* Status code can be specified in update handlers.
128* Support provides() in show functions.
129* _view_cleanup when ddoc has no views now removes all index files.
130* max_replication_retry_count now supports "infinity".
131* Fix replication crash when source database has a document with empty ID.
132* Fix deadlock when assigning couchjs processes to serve requests.
133* Fixes to the document multipart PUT API.
134* Fixes regarding file descriptor leaks for databases with views.
135
136Version 1.1.0
137-------------
138
139All CHANGES for 1.0.2 and 1.0.3 also apply to 1.1.0.
140
141HTTP Interface:
142
143 * Native SSL support.
144 * Added support for HTTP range requests for attachments.
145 * Added built-in filters for `_changes`: `_doc_ids` and `_design`.
146 * Added configuration option for TCP_NODELAY aka "Nagle".
147 * Allow POSTing arguments to `_changes`.
148 * Allow `keys` parameter for GET requests to views.
149 * Allow wildcards in vhosts definitions.
150 * More granular ETag support for views.
151 * More flexible URL rewriter.
152 * Added support for recognizing "Q values" and media parameters in
153 HTTP Accept headers.
154 * Validate doc ids that come from a PUT to a URL.
155
156Externals:
157
158 * Added OS Process module to manage daemons outside of CouchDB.
159 * Added HTTP Proxy handler for more scalable externals.
160
161Replicator:
162
163 * Added `_replicator` database to manage replications.
164 * Fixed issues when an endpoint is a remote database accessible via SSL.
165 * Added support for continuous by-doc-IDs replication.
166 * Fix issue where revision info was omitted when replicating attachments.
167 * Integrity of attachment replication is now verified by MD5.
168
169Storage System:
170
171 * Multiple micro-optimizations when reading data.
172
173View Server:
174
175 * Added CommonJS support to map functions.
176 * Added `stale=update_after` query option that triggers a view update after
177 returning a `stale=ok` response.
178 * Warn about empty result caused by `startkey` and `endkey` limiting.
179 * Built-in reduce function `_sum` now accepts lists of integers as input.
180 * Added view query aliases start_key, end_key, start_key_doc_id and
181 end_key_doc_id.
182
183Futon:
184
185 * Added a "change password"-feature to Futon.
186
187URL Rewriter & Vhosts:
188
189 * Fix for variable substituion
190
191Version 1.0.3
192-------------
193
194General:
195
196 * Fixed compatibility issues with Erlang R14B02.
197
198HTTP Interface:
199
200 * Fix bug that allows invalid UTF-8 after valid escapes.
201 * The query parameter `include_docs` now honors the parameter `conflicts`.
202 This applies to queries against map views, _all_docs and _changes.
203 * Added support for inclusive_end with reduce views.
204
205Storage System:
206
207 * More performant queries against _changes and _all_docs when using the
208 `include_docs` parameter.
209
210Replicator:
211
212 * Enabled replication over IPv6.
213 * Fixed for crashes in continuous and filtered changes feeds.
214 * Fixed error when restarting replications in OTP R14B02.
215 * Upgrade ibrowse to version 2.2.0.
216 * Fixed bug when using a filter and a limit of 1.
217
218Security:
219
220 * Fixed OAuth signature computation in OTP R14B02.
221 * Handle passwords with : in them.
222
223Futon:
224
225 * Made compatible with jQuery 1.5.x.
226
227Etap Test Suite:
228
229 * Etap tests no longer require use of port 5984. They now use a randomly
230 selected port so they won't clash with a running CouchDB.
231
232Windows:
233
234 * Windows builds now require ICU >= 4.4.0 and Erlang >= R14B03. See
235 COUCHDB-1152, and COUCHDB-963 + OTP-9139 for more information.
236
237Version 1.0.2
238-------------
239
240Futon:
241
242 * Make test suite work with Safari and Chrome.
243 * Fixed animated progress spinner.
244 * Fix raw view document link due to overzealous URI encoding.
245 * Spell javascript correctly in loadScript(uri).
246
247Storage System:
248
249 * Fix leaking file handles after compacting databases and views.
250 * Fix databases forgetting their validation function after compaction.
251 * Fix occasional timeout errors after successfully compacting large databases.
252 * Fix ocassional error when writing to a database that has just been compacted.
253 * Fix occasional timeout errors on systems with slow or heavily loaded IO.
254 * Fix for OOME when compactions include documents with many conflicts.
255 * Fix for missing attachment compression when MIME types included parameters.
256 * Preserve purge metadata during compaction to avoid spurious view rebuilds.
257 * Fix spurious conflicts introduced when uploading an attachment after
258 a doc has been in a conflict. See COUCHDB-902 for details.
259 * Fix for frequently edited documents in multi-master deployments being
260 duplicated in _changes and _all_docs. See COUCHDDB-968 for details on how
261 to repair.
262 * Significantly higher read and write throughput against database and
263 view index files.
264
265Log System:
266
267 * Reduce lengthy stack traces.
268 * Allow logging of native <xml> types.
269
270HTTP Interface:
271
272 * Allow reduce=false parameter in map-only views.
273 * Fix parsing of Accept headers.
274 * Fix for multipart GET APIs when an attachment was created during a
275 local-local replication. See COUCHDB-1022 for details.
276
277Replicator:
278
279 * Updated ibrowse library to 2.1.2 fixing numerous replication issues.
280 * Make sure that the replicator respects HTTP settings defined in the config.
281 * Fix error when the ibrowse connection closes unexpectedly.
282 * Fix authenticated replication (with HTTP basic auth) of design documents
283 with attachments.
284 * Various fixes to make replication more resilient for edge-cases.
285
286View Server:
287
288 * Don't trigger view updates when requesting `_design/doc/_info`.
289 * Fix for circular references in CommonJS requires.
290 * Made isArray() function available to functions executed in the query server.
291 * Documents are now sealed before being passed to map functions.
292 * Force view compaction failure when duplicated document data exists. When
293 this error is seen in the logs users should rebuild their views from
294 scratch to fix the issue. See COUCHDB-999 for details.
295
296Version 1.0.1
297-------------
298
299Storage System:
300
301 * Fix data corruption bug COUCHDB-844. Please see
302 http://couchdb.apache.org/notice/1.0.1.html for details.
303
304Replicator:
305
306 * Added support for replication via an HTTP/HTTPS proxy.
307 * Fix pull replication of attachments from 0.11 to 1.0.x.
308 * Make the _changes feed work with non-integer seqnums.
309
310HTTP Interface:
311
312 * Expose `committed_update_seq` for monitoring purposes.
313 * Show fields saved along with _deleted=true. Allows for auditing of deletes.
314 * More robust Accept-header detection.
315
316Authentication:
317
318 * Enable basic-auth popup when required to access the server, to prevent
319 people from getting locked out.
320
321Futon:
322
323 * User interface element for querying stale (cached) views.
324
325Build and System Integration:
326
327 * Included additional source files for distribution.
328
329Version 1.0.0
330-------------
331
332Security:
333
334 * Added authentication caching, to avoid repeated opening and closing of the
335 users database for each request requiring authentication.
336
337Storage System:
338
339 * Small optimization for reordering result lists.
340 * More efficient header commits.
341 * Use O_APPEND to save lseeks.
342 * Faster implementation of pread_iolist(). Further improves performance on
343 concurrent reads.
344
345View Server:
346
347 * Faster default view collation.
348 * Added option to include update_seq in view responses.
349
350Version 0.11.2
351--------------
352
353Replicator:
354
355 * Fix bug when pushing design docs by non-admins, which was hanging the
356 replicator for no good reason.
357 * Fix bug when pulling design documents from a source that requires
358 basic-auth.
359
360HTTP Interface:
361
362 * Better error messages on invalid URL requests.
363
364Authentication:
365
366 * User documents can now be deleted by admins or the user.
367
368Security:
369
370 * Avoid potential DOS attack by guarding all creation of atoms.
371
372Futon:
373
374 * Add some Futon files that were missing from the Makefile.
375
376Version 0.11.1
377--------------
378
379HTTP Interface:
380
381 * Mask passwords in active tasks and logging.
382 * Update mochijson2 to allow output of BigNums not in float form.
383 * Added support for X-HTTP-METHOD-OVERRIDE.
384 * Better error message for database names.
385 * Disable jsonp by default.
386 * Accept gzip encoded standalone attachments.
387 * Made max_concurrent_connections configurable.
388 * Made changes API more robust.
389 * Send newly generated document rev to callers of an update function.
390
391Futon:
392
393 * Use "expando links" for over-long document values in Futon.
394 * Added continuous replication option.
395 * Added option to replicating test results anonymously to a community
396 CouchDB instance.
397 * Allow creation and deletion of config entries.
398 * Fixed display issues with doc ids that have escaped characters.
399 * Fixed various UI issues.
400
401Build and System Integration:
402
403 * Output of `couchdb --help` has been improved.
404 * Fixed compatibility with the Erlang R14 series.
405 * Fixed warnings on Linux builds.
406 * Fixed build error when aclocal needs to be called during the build.
407 * Require ICU 4.3.1.
408 * Fixed compatibility with Solaris.
409
410Security:
411
412 * Added authentication redirect URL to log in clients.
413 * Fixed query parameter encoding issue in oauth.js.
414 * Made authentication timeout configurable.
415 * Temporary views are now admin-only resources.
416
417Storage System:
418
419 * Don't require a revpos for attachment stubs.
420 * Added checking to ensure when a revpos is sent with an attachment stub,
421 it's correct.
422 * Make file deletions async to avoid pauses during compaction and db
423 deletion.
424 * Fixed for wrong offset when writing headers and converting them to blocks,
425 only triggered when header is larger than 4k.
426 * Preserve _revs_limit and instance_start_time after compaction.
427
428Configuration System:
429
430 * Fixed timeout with large .ini files.
431
432JavaScript Clients:
433
434 * Added tests for couch.js and jquery.couch.js
435 * Added changes handler to jquery.couch.js.
436 * Added cache busting to jquery.couch.js if the user agent is msie.
437 * Added support for multi-document-fetch (via _all_docs) to jquery.couch.js.
438 * Added attachment versioning to jquery.couch.js.
439 * Added option to control ensure_full_commit to jquery.couch.js.
440 * Added list functionality to jquery.couch.js.
441 * Fixed issues where bulkSave() wasn't sending a POST body.
442
443View Server:
444
445 * Provide a UUID to update functions (and all other functions) that they can
446 use to create new docs.
447 * Upgrade CommonJS modules support to 1.1.1.
448 * Fixed erlang filter funs and normalize filter fun API.
449 * Fixed hang in view shutdown.
450
451Log System:
452
453 * Log HEAD requests as HEAD, not GET.
454 * Keep massive JSON blobs out of the error log.
455 * Fixed a timeout issue.
456
457Replication System:
458
459 * Refactored various internal APIs related to attachment streaming.
460 * Fixed hanging replication.
461 * Fixed keepalive issue.
462
463URL Rewriter & Vhosts:
464
465 * Allow more complex keys in rewriter.
466 * Allow global rewrites so system defaults are available in vhosts.
467 * Allow isolation of databases with vhosts.
468 * Fix issue with passing variables to query parameters.
469
470Test Suite:
471
472 * Made the test suite overall more reliable.
473
474Version 0.11.0
475--------------
476
477Security:
478
479 * Fixed CVE-2010-0009: Apache CouchDB Timing Attack Vulnerability.
480 * Added default cookie-authentication and users database.
481 * Added Futon user interface for user signup and login.
482 * Added per-database reader access control lists.
483 * Added per-database security object for configuration data in validation
484 functions.
485 * Added proxy authentication handler
486
487HTTP Interface:
488
489 * Provide Content-MD5 header support for attachments.
490 * Added URL Rewriter handler.
491 * Added virtual host handling.
492
493View Server:
494
495 * Added optional 'raw' binary collation for faster view builds where Unicode
496 collation is not important.
497 * Improved view index build time by reducing ICU collation callouts.
498 * Improved view information objects.
499 * Bug fix for partial updates during view builds.
500 * Move query server to a design-doc based protocol.
501 * Use json2.js for JSON serialization for compatiblity with native JSON.
502 * Major refactoring of couchjs to lay the groundwork for disabling cURL
503 support. The new HTTP interaction acts like a synchronous XHR. Example usage
504 of the new system is in the JavaScript CLI test runner.
505
506Replication:
507
508 * Added option to implicitly create replication target databases.
509 * Avoid leaking file descriptors on automatic replication restarts.
510 * Added option to replicate a list of documents by id.
511 * Allow continuous replication to be cancelled.
512
513Storage System:
514
515 * Adds batching of multiple updating requests, to improve throughput with many
516 writers. Removed the now redundant couch_batch_save module.
517 * Adds configurable compression of attachments.
518
519Runtime Statistics:
520
521 * Statistics are now calculated for a moving window instead of non-overlapping
522 timeframes.
523 * Fixed a problem with statistics timers and system sleep.
524 * Moved statistic names to a term file in the priv directory.
525
526Futon:
527
528 * Added a button for view compaction.
529 * JSON strings are now displayed as-is in the document view, without the escaping of
530 new-lines and quotes. That dramatically improves readability of multi-line
531 strings.
532 * Same goes for editing of JSON string values. When a change to a field value is
533 submitted, and the value is not valid JSON it is assumed to be a string. This
534 improves editing of multi-line strings a lot.
535 * Hitting tab in textareas no longer moves focus to the next form field, but simply
536 inserts a tab character at the current caret position.
537 * Fixed some font declarations.
538
539Build and System Integration:
540
541 * Updated and improved source documentation.
542 * Fixed distribution preparation for building on Mac OS X.
543 * Added support for building a Windows installer as part of 'make dist'.
544 * Bug fix for building couch.app's module list.
545 * ETap tests are now run during make distcheck. This included a number of
546 updates to the build system to properly support VPATH builds.
547 * Gavin McDonald setup a build-bot instance. More info can be found at
548 http://ci.apache.org/buildbot.html
549
550Version 0.10.1
551--------------
552
553Replicator:
554
555 * Stability enhancements regarding redirects, timeouts, OAuth.
556
557Query Server:
558
559 * Avoid process leaks
560 * Allow list and view to span languages
561
562Stats:
563
564 * Eliminate new process flood on system wake
565
566Build and System Integration:
567
568 * Test suite now works with the distcheck target.
569
570Version 0.10.0
571--------------
572
573Storage Format:
574
575 * Add move headers with checksums to the end of database files for extra robust
576 storage and faster storage.
577
578View Server:
579
580 * Added native Erlang views for high-performance applications.
581
582HTTP Interface:
583
584 * Added optional cookie-based authentication handler.
585 * Added optional two-legged OAuth authentication handler.
586
587Build and System Integration:
588
589 * Changed `couchdb` script configuration options.
590 * Added default.d and local.d configuration directories to load sequence.
591
592
593Version 0.9.2
594-------------
595
596Replication:
597
598 * Fix replication with 0.10 servers initiated by an 0.9 server (COUCHDB-559).
599
600Build and System Integration:
601
602 * Remove branch callbacks to allow building couchjs against newer versions of
603 Spidermonkey.
604
605Version 0.9.1
606-------------
607
608Build and System Integration:
609
610 * PID file directory is now created by the SysV/BSD daemon scripts.
611 * Fixed the environment variables shown by the configure script.
612 * Fixed the build instructions shown by the configure script.
613 * Updated ownership and permission advice in `README` for better security.
614
615Configuration and stats system:
616
617 * Corrected missing configuration file error message.
618 * Fixed incorrect recording of request time.
619
620Database Core:
621
622 * Document validation for underscore prefixed variables.
623 * Made attachment storage less sparse.
624 * Fixed problems when a database with delayed commits pending is considered
625 idle, and subject to losing changes when shutdown. (COUCHDB-334)
626
627External Handlers:
628
629 * Fix POST requests.
630
631Futon:
632
633 * Redirect when loading a deleted view URI from the cookie.
634
635HTTP Interface:
636
637 * Attachment requests respect the "rev" query-string parameter.
638
639JavaScript View Server:
640
641 * Useful JavaScript Error messages.
642
643Replication:
644
645 * Added support for Unicode characters transmitted as UTF-16 surrogate pairs.
646 * URL-encode attachment names when necessary.
647 * Pull specific revisions of an attachment, instead of just the latest one.
648 * Work around a rare chunk-merging problem in ibrowse.
649 * Work with documents containing Unicode characters outside the Basic
650 Multilingual Plane.
651
652Version 0.9.0
653-------------
654
655Futon Utility Client:
656
657 * Added pagination to the database listing page.
658 * Implemented attachment uploading from the document page.
659 * Added page that shows the current configuration, and allows modification of
660 option values.
661 * Added a JSON "source view" for document display.
662 * JSON data in view rows is now syntax highlighted.
663 * Removed the use of an iframe for better integration with browser history and
664 bookmarking.
665 * Full database listing in the sidebar has been replaced by a short list of
666 recent databases.
667 * The view editor now allows selection of the view language if there is more
668 than one configured.
669 * Added links to go to the raw view or document URI.
670 * Added status page to display currently running tasks in CouchDB.
671 * JavaScript test suite split into multiple files.
672 * Pagination for reduce views.
673
674Design Document Resource Paths:
675
676 * Added httpd_design_handlers config section.
677 * Moved _view to httpd_design_handlers.
678 * Added ability to render documents as non-JSON content-types with _show and
679 _list functions, which are also httpd_design_handlers.
680
681HTTP Interface:
682
683 * Added client side UUIDs for idempotent document creation
684 * HTTP COPY for documents
685 * Streaming of chunked attachment PUTs to disk
686 * Remove negative count feature
687 * Add include_docs option for view queries
688 * Add multi-key view post for views
689 * Query parameter validation
690 * Use stale=ok to request potentially cached view index
691 * External query handler module for full-text or other indexers.
692 * Etags for attachments, views, shows and lists
693 * Show and list functions for rendering documents and views as developer
694 controlled content-types.
695 * Attachment names may use slashes to allow uploading of nested directories
696 (useful for static web hosting).
697 * Option for a view to run over design documents.
698 * Added newline to JSON responses. Closes bike-shed.
699
700Replication:
701
702 * Using ibrowse.
703 * Checkpoint replications so failures are less expensive.
704 * Automatically retry of failed replications.
705 * Stream attachments in pull-replication.
706
707Database Core:
708
709 * Faster B-tree implementation.
710 * Changed internal JSON term format.
711 * Improvements to Erlang VM interactions under heavy load.
712 * User context and administrator role.
713 * Update validations with design document validation functions.
714 * Document purge functionality.
715 * Ref-counting for database file handles.
716
717Build and System Integration:
718
719 * The `couchdb` script now supports system chainable configuration files.
720 * The Mac OS X daemon script now redirects STDOUT and STDERR like SysV/BSD.
721 * The build and system integration have been improved for portability.
722 * Added COUCHDB_OPTIONS to etc/default/couchdb file.
723 * Remove COUCHDB_INI_FILE and COUCHDB_PID_FILE from etc/default/couchdb file.
724 * Updated `configure.ac` to manually link `libm` for portability.
725 * Updated `configure.ac` to extended default library paths.
726 * Removed inets configuration files.
727 * Added command line test runner.
728 * Created dev target for make.
729
730Configuration and stats system:
731
732 * Separate default and local configuration files.
733 * HTTP interface for configuration changes.
734 * Statistics framework with HTTP query API.
735
736Version 0.8.1-incubating
737------------------------
738
739Database Core:
740
741 * Fix for replication problems where the write queues can get backed up if the
742 writes aren't happening fast enough to keep up with the reads. For a large
743 replication, this can exhaust memory and crash, or slow down the machine
744 dramatically. The fix keeps only one document in the write queue at a time.
745 * Fix for databases sometimes incorrectly reporting that they contain 0
746 documents after compaction.
747 * CouchDB now uses ibrowse instead of inets for its internal HTTP client
748 implementation. This means better replication stability.
749
750HTTP Interface:
751
752 * Fix for chunked responses where chunks were always being split into multiple
753 TCP packets, which caused problems with the test suite under Safari, and in
754 some other cases.
755 * Fix for an invalid JSON response body being returned for some kinds of
756 views. (COUCHDB-84)
757 * Fix for connections not getting closed after rejecting a chunked request.
758 (COUCHDB-55)
759 * CouchDB can now be bound to IPv6 addresses.
760 * The HTTP `Server` header now contains the versions of CouchDB and Erlang.
761
762JavaScript View Server:
763
764 * Sealing of documents has been disabled due to an incompatibility with
765 SpiderMonkey 1.9.
766 * Improve error handling for undefined values emitted by map functions.
767 (COUCHDB-83)
768
769Build and System Integration:
770
771 * The `couchdb` script no longer uses `awk` for configuration checks as this
772 was causing portability problems.
773 * Updated `sudo` example in `README` to use the `-i` option, this fixes
774 problems when invoking from a directory the `couchdb` user cannot access.
775
776Futon:
777
778 * The view selector dropdown should now work in Opera and Internet Explorer
779 even when it includes optgroups for design documents. (COUCHDB-81)
780
781Version 0.8.0-incubating
782------------------------
783
784Database Core:
785
786 * The view engine has been completely decoupled from the storage engine. Index
787 data is now stored in separate files, and the format of the main database
788 file has changed.
789 * Databases can now be compacted to reclaim space used for deleted documents
790 and old document revisions.
791 * Support for incremental map/reduce views has been added.
792 * To support map/reduce, the structure of design documents has changed. View
793 values are now JSON objects containing at least a `map` member, and
794 optionally a `reduce` member.
795 * View servers are now identified by name (for example `javascript`) instead of
796 by media type.
797 * Automatically generated document IDs are now based on proper UUID generation
798 using the crypto module.
799 * The field `content-type` in the JSON representation of attachments has been
800 renamed to `content_type` (underscore).
801
802HTTP Interface:
803
804 * CouchDB now uses MochiWeb instead of inets for the HTTP server
805 implementation. Among other things, this means that the extra configuration
806 files needed for inets (such as `couch_httpd.conf`) are no longer used.
807 * The HTTP interface now completely supports the `HEAD` method. (COUCHDB-3)
808 * Improved compliance of `Etag` handling with the HTTP specification.
809 (COUCHDB-13)
810 * Etags are no longer included in responses to document `GET` requests that
811 include query string parameters causing the JSON response to change without
812 the revision or the URI having changed.
813 * The bulk document update API has changed slightly on both the request and the
814 response side. In addition, bulk updates are now atomic.
815 * CouchDB now uses `TCP_NODELAY` to fix performance problems with persistent
816 connections on some platforms due to nagling.
817 * Including a `?descending=false` query string parameter in requests to views
818 no longer raises an error.
819 * Requests to unknown top-level reserved URLs (anything with a leading
820 underscore) now return a `unknown_private_path` error instead of the
821 confusing `illegal_database_name`.
822 * The Temporary view handling now expects a JSON request body, where the JSON
823 is an object with at least a `map` member, and optional `reduce` and
824 `language` members.
825 * Temporary views no longer determine the view server based on the Content-Type
826 header of the `POST` request, but rather by looking for a `language` member
827 in the JSON body of the request.
828 * The status code of responses to `DELETE` requests is now 200 to reflect that
829 that the deletion is performed synchronously.
830
831JavaScript View Server:
832
833 * SpiderMonkey is no longer included with CouchDB, but rather treated as a
834 normal external dependency. A simple C program (`_couchjs`) is provided that
835 links against an existing SpiderMonkey installation and uses the interpreter
836 embedding API.
837 * View functions using the default JavaScript view server can now do logging
838 using the global `log(message)` function. Log messages are directed into the
839 CouchDB log at `INFO` level. (COUCHDB-59)
840 * The global `map(key, value)` function made available to view code has been
841 renamed to `emit(key, value)`.
842 * Fixed handling of exceptions raised by view functions.
843
844Build and System Integration:
845
846 * CouchDB can automatically respawn following a server crash.
847 * Database server no longer refuses to start with a stale PID file.
848 * System logrotate configuration provided.
849 * Improved handling of ICU shared libraries.
850 * The `couchdb` script now automatically enables SMP support in Erlang.
851 * The `couchdb` and `couchjs` scripts have been improved for portability.
852 * The build and system integration have been improved for portability.
853
854Futon:
855
856 * When adding a field to a document, Futon now just adds a field with an
857 autogenerated name instead of prompting for the name with a dialog. The name
858 is automatically put into edit mode so that it can be changed immediately.
859 * Fields are now sorted alphabetically by name when a document is displayed.
860 * Futon can be used to create and update permanent views.
861 * The maximum number of rows to display per page on the database page can now
862 be adjusted.
863 * Futon now uses the XMLHTTPRequest API asynchronously to communicate with the
864 CouchDB HTTP server, so that most operations no longer block the browser.
865 * View results sorting can now be switched between ascending and descending by
866 clicking on the `Key` column header.
867 * Fixed a bug where documents that contained a `@` character could not be
868 viewed. (COUCHDB-12)
869 * The database page now provides a `Compact` button to trigger database
870 compaction. (COUCHDB-38)
871 * Fixed portential double encoding of document IDs and other URI segments in
872 many instances. (COUCHDB-39)
873 * Improved display of attachments.
874 * The JavaScript Shell has been removed due to unresolved licensing issues.
8750
=== modified file 'DEVELOPERS'
--- DEVELOPERS 2010-07-26 10:24:11 +0000
+++ DEVELOPERS 2013-08-30 22:06:57 +0000
@@ -1,6 +1,10 @@
1Apache CouchDB DEVELOPERS1Apache CouchDB DEVELOPERS
2=========================2=========================
33
4Before you start here, read `INSTALL.Unix` (or `INSTALL.Windows`) and
5follow the setup instructions including the installation of all the
6listed dependencies for your system.
7
4Only follow these instructions if you are building from a source checkout.8Only follow these instructions if you are building from a source checkout.
59
6If you're unsure what this means, ignore this document.10If you're unsure what this means, ignore this document.
@@ -10,30 +14,109 @@
1014
11You will need the following installed:15You will need the following installed:
1216
17 * GNU Libtool (http://www.gnu.org/software/libtool/)
13 * GNU Automake (>=1.6.3) (http://www.gnu.org/software/automake/)18 * GNU Automake (>=1.6.3) (http://www.gnu.org/software/automake/)
14 * GNU Autoconf (>=2.59) (http://www.gnu.org/software/autoconf/)19 * GNU Autoconf (>=2.63) (http://www.gnu.org/software/autoconf/)
15 * GNU Libtool (http://www.gnu.org/software/libtool/)20 * GNU Autoconf Archive (http://www.gnu.org/software/autoconf-archive/)
21 * pkg-config (http://www.freedesktop.org/wiki/Software/pkg-config)
22
23You may also need:
24
25 * Sphinx (http://sphinx.pocoo.org/)
26 * LaTex (http://www.latex-project.org/)
27 * GNU Texinfo (http://www.gnu.org/software/texinfo/)
16 * GNU help2man (http://www.gnu.org/software/help2man/)28 * GNU help2man (http://www.gnu.org/software/help2man/)
1729 * GnuPG (http://www.gnupg.org/)
18The `help2man` tool is optional, but will generate `man` pages for you.30 * md5sum (http://www.microbrew.org/tools/md5sha1sum/)
31 * sha1sum (http://www.microbrew.org/tools/md5sha1sum/)
32
33The first of these optional dependencies are required for building the
34documentation. The last three are needed to build releases.
35
36You will need these optional dependencies installed if:
37
38 * You are working on the documentation, or
39 * You are preparing a distribution archive
40
41However, you do not need them if:
42
43 * You are building from a distribution archive, or
44 * You don't care about building the documentation
45
46
47Here is a list of *optional* dependencies for various operating systems.
48Installation will be easiest, when you install them all.
1949
20Debian-based (inc. Ubuntu) Systems50Debian-based (inc. Ubuntu) Systems
21~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~51~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2252
23You can install the dependencies by running:53 sudo apt-get install help2man
2454 sudo apt-get install python-sphinx
25 apt-get install automake autoconf libtool help2man55 sudo apt-get install texlive-latex-base
2656 sudo apt-get install texlive-latex-recommended
27Be sure to update the version numbers to match your system's available packages.57 sudo apt-get install texlive-latex-extra
58 sudo apt-get install texlive-fonts-recommended
59 sudo apt-get install texinfo
60 sudo apt-get install gnupg
61
62Gentoo-based Systems
63~~~~~~~~~~~~~~~~~~~~
64
65 sudo emerge texinfo
66 sudo emerge gnupg
67 sudo emerge coreutils
68 sudo emerge pkgconfig
69 sudo emerge help2man
70 sudo USE=latex emerge sphinx
71
72RedHat-based (Fedora, Centos, RHEL) Systems
73~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
74
75 sudo yum install help2man
76 sudo yum install python-sphinx
77 sudo yum install python-docutils
78 sudo yum install python-pygments
79 sudo yum install texlive-latex
80 sudo yum install texlive-latex-fonts
81 sudo yum install texinfo
82 sudo yum install gnupg
2883
29Mac OS X84Mac OS X
30~~~~~~~~85~~~~~~~~
3186
32You can install the dependencies by running:87Install Homebrew, if you do not have it already:
3388
34 port install automake autoconf libtool help2man89 https://github.com/mxcl/homebrew
3590
36You will need MacPorts installed to use the `port` command.91Unless you want to install the optional dependencies, skip to the next section.
92
93Install what else we can with Homebrew:
94
95 brew install help2man
96 brew install gnupg
97 brew install md5sha1sum
98
99If you don't already have pip installed, install it:
100
101 sudo easy_install pip
102
103Now, install the required Python packages:
104
105 sudo pip install sphinx
106 sudo pip install docutils
107 sudo pip install pygments
108
109Download MaxTeX from here:
110
111 http://www.tug.org/mactex/
112
113Follow the instructions to get a working LaTeX install on your system.
114
115Windows
116~~~~~~~
117
118Follow the instructions in INSTALL.Windows and build all components from
119source, using the same Visual C++ compiler and runtime.
37120
38Bootstrapping121Bootstrapping
39-------------122-------------
@@ -44,6 +127,33 @@
44127
45You must repeat this step every time you update your source checkout.128You must repeat this step every time you update your source checkout.
46129
130Configuring
131-----------
132
133Configure the source by running:
134
135 ./configure
136
137Note that this will not fail when the optional dependencies are missing.
138
139To ensure the optional dependencies are installed, run:
140
141 ./configure --enable-strictness
142
143If you don't care about docs and want to skip the whole thing, run:
144
145 ./configure --disable-docs
146
147If you're working on the build system itself, you can run:
148
149 ./configure --disable-tests
150
151This skips the tests allowing quicker `make' cycles.
152
153If you want to build it into different destination than `/usr/local`.
154
155 ./configure --prefix=/<your directory path>
156
47Testing157Testing
48-------158-------
49159
@@ -60,13 +170,13 @@
60Releasing170Releasing
61---------171---------
62172
173The release procedure is documented here:
174
175 https://wiki.apache.org/couchdb/Release_Procedure
176
63Unix-like Systems177Unix-like Systems
64~~~~~~~~~~~~~~~~~178~~~~~~~~~~~~~~~~~
65179
66Configure the source by running:
67
68 ./configure
69
70Prepare the release artefacts by running:180Prepare the release artefacts by running:
71181
72 make distcheck182 make distcheck
@@ -80,10 +190,6 @@
80Microsoft Windows190Microsoft Windows
81~~~~~~~~~~~~~~~~~191~~~~~~~~~~~~~~~~~
82192
83Configure the source by running:
84
85 ./configure
86
87Prepare the release artefacts by running:193Prepare the release artefacts by running:
88194
89 make dist195 make dist
90196
=== modified file 'INSTALL'
--- INSTALL 2012-07-30 22:49:54 +0000
+++ INSTALL 2013-08-30 22:06:57 +0000
@@ -1,19 +1,25 @@
1Installation Instructions1Installation Instructions
2*************************2*************************
33
4Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,4Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
52006 Free Software Foundation, Inc.5Inc.
66
7This file is free documentation; the Free Software Foundation gives7 Copying and distribution of this file, with or without modification,
8unlimited permission to copy, distribute and modify it.8are permitted in any medium without royalty provided the copyright
9notice and this notice are preserved. This file is offered as-is,
10without warranty of any kind.
911
10Basic Installation12Basic Installation
11==================13==================
1214
13Briefly, the shell commands `./configure; make; make install' should15 Briefly, the shell commands `./configure; make; make install' should
14configure, build, and install this package. The following16configure, build, and install this package. The following
15more-detailed instructions are generic; see the `README' file for17more-detailed instructions are generic; see the `README' file for
16instructions specific to this package.18instructions specific to this package. Some packages provide this
19`INSTALL' file but do not implement all of the features documented
20below. The lack of an optional feature in a given package is not
21necessarily a bug. More recommendations for GNU packages can be found
22in *note Makefile Conventions: (standards)Makefile Conventions.
1723
18 The `configure' shell script attempts to guess correct values for24 The `configure' shell script attempts to guess correct values for
19various system-dependent variables used during compilation. It uses25various system-dependent variables used during compilation. It uses
@@ -42,7 +48,7 @@
42you want to change it or regenerate `configure' using a newer version48you want to change it or regenerate `configure' using a newer version
43of `autoconf'.49of `autoconf'.
4450
45The simplest way to compile this package is:51 The simplest way to compile this package is:
4652
47 1. `cd' to the directory containing the package's source code and type53 1. `cd' to the directory containing the package's source code and type
48 `./configure' to configure the package for your system.54 `./configure' to configure the package for your system.
@@ -53,12 +59,22 @@
53 2. Type `make' to compile the package.59 2. Type `make' to compile the package.
5460
55 3. Optionally, type `make check' to run any self-tests that come with61 3. Optionally, type `make check' to run any self-tests that come with
56 the package.62 the package, generally using the just-built uninstalled binaries.
5763
58 4. Type `make install' to install the programs and any data files and64 4. Type `make install' to install the programs and any data files and
59 documentation.65 documentation. When installing into a prefix owned by root, it is
6066 recommended that the package be configured and built as a regular
61 5. You can remove the program binaries and object files from the67 user, and only the `make install' phase executed with root
68 privileges.
69
70 5. Optionally, type `make installcheck' to repeat any self-tests, but
71 this time using the binaries in their final installed location.
72 This target does not install anything. Running this target as a
73 regular user, particularly if the prior `make install' required
74 root privileges, verifies that the installation completed
75 correctly.
76
77 6. You can remove the program binaries and object files from the
62 source code directory by typing `make clean'. To also remove the78 source code directory by typing `make clean'. To also remove the
63 files that `configure' created (so you can compile the package for79 files that `configure' created (so you can compile the package for
64 a different kind of computer), type `make distclean'. There is80 a different kind of computer), type `make distclean'. There is
@@ -67,12 +83,22 @@
67 all sorts of other programs in order to regenerate files that came83 all sorts of other programs in order to regenerate files that came
68 with the distribution.84 with the distribution.
6985
86 7. Often, you can also type `make uninstall' to remove the installed
87 files again. In practice, not all packages have tested that
88 uninstallation works correctly, even though it is required by the
89 GNU Coding Standards.
90
91 8. Some packages, particularly those that use Automake, provide `make
92 distcheck', which can by used by developers to test that all other
93 targets like `make install' and `make uninstall' work correctly.
94 This target is generally not run by end users.
95
70Compilers and Options96Compilers and Options
71=====================97=====================
7298
73Some systems require unusual options for compilation or linking that the99 Some systems require unusual options for compilation or linking that
74`configure' script does not know about. Run `./configure --help' for100the `configure' script does not know about. Run `./configure --help'
75details on some of the pertinent environment variables.101for details on some of the pertinent environment variables.
76102
77 You can give `configure' initial values for configuration parameters103 You can give `configure' initial values for configuration parameters
78by setting variables in the command line or in the environment. Here104by setting variables in the command line or in the environment. Here
@@ -85,25 +111,41 @@
85Compiling For Multiple Architectures111Compiling For Multiple Architectures
86====================================112====================================
87113
88You can compile the package for more than one kind of computer at the114 You can compile the package for more than one kind of computer at the
89same time, by placing the object files for each architecture in their115same time, by placing the object files for each architecture in their
90own directory. To do this, you can use GNU `make'. `cd' to the116own directory. To do this, you can use GNU `make'. `cd' to the
91directory where you want the object files and executables to go and run117directory where you want the object files and executables to go and run
92the `configure' script. `configure' automatically checks for the118the `configure' script. `configure' automatically checks for the
93source code in the directory that `configure' is in and in `..'.119source code in the directory that `configure' is in and in `..'. This
120is known as a "VPATH" build.
94121
95 With a non-GNU `make', it is safer to compile the package for one122 With a non-GNU `make', it is safer to compile the package for one
96architecture at a time in the source code directory. After you have123architecture at a time in the source code directory. After you have
97installed the package for one architecture, use `make distclean' before124installed the package for one architecture, use `make distclean' before
98reconfiguring for another architecture.125reconfiguring for another architecture.
99126
127 On MacOS X 10.5 and later systems, you can create libraries and
128executables that work on multiple system types--known as "fat" or
129"universal" binaries--by specifying multiple `-arch' options to the
130compiler but only a single `-arch' option to the preprocessor. Like
131this:
132
133 ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
134 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
135 CPP="gcc -E" CXXCPP="g++ -E"
136
137 This is not guaranteed to produce working output in all cases, you
138may have to build one architecture at a time and combine the results
139using the `lipo' tool if you have problems.
140
100Installation Names141Installation Names
101==================142==================
102143
103By default, `make install' installs the package's commands under144 By default, `make install' installs the package's commands under
104`/usr/local/bin', include files under `/usr/local/include', etc. You145`/usr/local/bin', include files under `/usr/local/include', etc. You
105can specify an installation prefix other than `/usr/local' by giving146can specify an installation prefix other than `/usr/local' by giving
106`configure' the option `--prefix=PREFIX'.147`configure' the option `--prefix=PREFIX', where PREFIX must be an
148absolute file name.
107149
108 You can specify separate installation prefixes for150 You can specify separate installation prefixes for
109architecture-specific files and architecture-independent files. If you151architecture-specific files and architecture-independent files. If you
@@ -114,16 +156,47 @@
114 In addition, if you use an unusual directory layout you can give156 In addition, if you use an unusual directory layout you can give
115options like `--bindir=DIR' to specify different values for particular157options like `--bindir=DIR' to specify different values for particular
116kinds of files. Run `configure --help' for a list of the directories158kinds of files. Run `configure --help' for a list of the directories
117you can set and what kinds of files go in them.159you can set and what kinds of files go in them. In general, the
160default for these options is expressed in terms of `${prefix}', so that
161specifying just `--prefix' will affect all of the other directory
162specifications that were not explicitly provided.
163
164 The most portable way to affect installation locations is to pass the
165correct locations to `configure'; however, many packages provide one or
166both of the following shortcuts of passing variable assignments to the
167`make install' command line to change installation locations without
168having to reconfigure or recompile.
169
170 The first method involves providing an override variable for each
171affected directory. For example, `make install
172prefix=/alternate/directory' will choose an alternate location for all
173directory configuration variables that were expressed in terms of
174`${prefix}'. Any directories that were specified during `configure',
175but not in terms of `${prefix}', must each be overridden at install
176time for the entire installation to be relocated. The approach of
177makefile variable overrides for each directory variable is required by
178the GNU Coding Standards, and ideally causes no recompilation.
179However, some platforms have known limitations with the semantics of
180shared libraries that end up requiring recompilation when using this
181method, particularly noticeable in packages that use GNU Libtool.
182
183 The second method involves providing the `DESTDIR' variable. For
184example, `make install DESTDIR=/alternate/directory' will prepend
185`/alternate/directory' before all installation names. The approach of
186`DESTDIR' overrides is not required by the GNU Coding Standards, and
187does not work on platforms that have drive letters. On the other hand,
188it does better at avoiding recompilation issues, and works well even
189when some directory options were not specified in terms of `${prefix}'
190at `configure' time.
191
192Optional Features
193=================
118194
119 If the package supports it, you can cause programs to be installed195 If the package supports it, you can cause programs to be installed
120with an extra prefix or suffix on their names by giving `configure' the196with an extra prefix or suffix on their names by giving `configure' the
121option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.197option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
122198
123Optional Features199 Some packages pay attention to `--enable-FEATURE' options to
124=================
125
126Some packages pay attention to `--enable-FEATURE' options to
127`configure', where FEATURE indicates an optional part of the package.200`configure', where FEATURE indicates an optional part of the package.
128They may also pay attention to `--with-PACKAGE' options, where PACKAGE201They may also pay attention to `--with-PACKAGE' options, where PACKAGE
129is something like `gnu-as' or `x' (for the X Window System). The202is something like `gnu-as' or `x' (for the X Window System). The
@@ -135,14 +208,58 @@
135you can use the `configure' options `--x-includes=DIR' and208you can use the `configure' options `--x-includes=DIR' and
136`--x-libraries=DIR' to specify their locations.209`--x-libraries=DIR' to specify their locations.
137210
211 Some packages offer the ability to configure how verbose the
212execution of `make' will be. For these packages, running `./configure
213--enable-silent-rules' sets the default to minimal output, which can be
214overridden with `make V=1'; while running `./configure
215--disable-silent-rules' sets the default to verbose, which can be
216overridden with `make V=0'.
217
218Particular systems
219==================
220
221 On HP-UX, the default C compiler is not ANSI C compatible. If GNU
222CC is not installed, it is recommended to use the following options in
223order to use an ANSI C compiler:
224
225 ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
226
227and if that doesn't work, install pre-built binaries of GCC for HP-UX.
228
229 HP-UX `make' updates targets which have the same time stamps as
230their prerequisites, which makes it generally unusable when shipped
231generated files such as `configure' are involved. Use GNU `make'
232instead.
233
234 On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
235parse its `<wchar.h>' header file. The option `-nodtk' can be used as
236a workaround. If GNU CC is not installed, it is therefore recommended
237to try
238
239 ./configure CC="cc"
240
241and if that doesn't work, try
242
243 ./configure CC="cc -nodtk"
244
245 On Solaris, don't put `/usr/ucb' early in your `PATH'. This
246directory contains several dysfunctional programs; working variants of
247these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
248in your `PATH', put it _after_ `/usr/bin'.
249
250 On Haiku, software installed for all users goes in `/boot/common',
251not `/usr/local'. It is recommended to use the following options:
252
253 ./configure --prefix=/boot/common
254
138Specifying the System Type255Specifying the System Type
139==========================256==========================
140257
141There may be some features `configure' cannot figure out automatically,258 There may be some features `configure' cannot figure out
142but needs to determine by the type of machine the package will run on.259automatically, but needs to determine by the type of machine the package
143Usually, assuming the package is built to be run on the _same_260will run on. Usually, assuming the package is built to be run on the
144architectures, `configure' can figure that out, but if it prints a261_same_ architectures, `configure' can figure that out, but if it prints
145message saying it cannot guess the machine type, give it the262a message saying it cannot guess the machine type, give it the
146`--build=TYPE' option. TYPE can either be a short name for the system263`--build=TYPE' option. TYPE can either be a short name for the system
147type, such as `sun4', or a canonical name which has the form:264type, such as `sun4', or a canonical name which has the form:
148265
@@ -150,7 +267,8 @@
150267
151where SYSTEM can have one of these forms:268where SYSTEM can have one of these forms:
152269
153 OS KERNEL-OS270 OS
271 KERNEL-OS
154272
155 See the file `config.sub' for the possible values of each field. If273 See the file `config.sub' for the possible values of each field. If
156`config.sub' isn't included in this package, then this package doesn't274`config.sub' isn't included in this package, then this package doesn't
@@ -168,9 +286,9 @@
168Sharing Defaults286Sharing Defaults
169================287================
170288
171If you want to set default values for `configure' scripts to share, you289 If you want to set default values for `configure' scripts to share,
172can create a site shell script called `config.site' that gives default290you can create a site shell script called `config.site' that gives
173values for variables like `CC', `cache_file', and `prefix'.291default values for variables like `CC', `cache_file', and `prefix'.
174`configure' looks for `PREFIX/share/config.site' if it exists, then292`configure' looks for `PREFIX/share/config.site' if it exists, then
175`PREFIX/etc/config.site' if it exists. Or, you can set the293`PREFIX/etc/config.site' if it exists. Or, you can set the
176`CONFIG_SITE' environment variable to the location of the site script.294`CONFIG_SITE' environment variable to the location of the site script.
@@ -179,7 +297,7 @@
179Defining Variables297Defining Variables
180==================298==================
181299
182Variables not defined in a site shell script can be set in the300 Variables not defined in a site shell script can be set in the
183environment passed to `configure'. However, some packages may run301environment passed to `configure'. However, some packages may run
184configure again during the build, and the customized values of these302configure again during the build, and the customized values of these
185variables may be lost. In order to avoid this problem, you should set303variables may be lost. In order to avoid this problem, you should set
@@ -198,11 +316,19 @@
198`configure' Invocation316`configure' Invocation
199======================317======================
200318
201`configure' recognizes the following options to control how it operates.319 `configure' recognizes the following options to control how it
320operates.
202321
203`--help'322`--help'
204`-h'323`-h'
205 Print a summary of the options to `configure', and exit.324 Print a summary of all of the options to `configure', and exit.
325
326`--help=short'
327`--help=recursive'
328 Print a summary of the options unique to this package's
329 `configure', and exit. The `short' variant lists options used
330 only in the top level, while the `recursive' variant lists options
331 also present in any nested packages.
206332
207`--version'333`--version'
208`-V'334`-V'
@@ -229,6 +355,16 @@
229 Look for the package's source code in directory DIR. Usually355 Look for the package's source code in directory DIR. Usually
230 `configure' can determine that directory automatically.356 `configure' can determine that directory automatically.
231357
358`--prefix=DIR'
359 Use DIR as the installation prefix. *note Installation Names::
360 for more details, including other options available for fine-tuning
361 the installation locations.
362
363`--no-create'
364`-n'
365 Run the configure checks, but stop before creating any output
366 files.
367
232`configure' also accepts some other, not widely useful, options. Run368`configure' also accepts some other, not widely useful, options. Run
233`configure --help' for more details.369`configure --help' for more details.
234370
235371
=== modified file 'INSTALL.Unix'
--- INSTALL.Unix 2012-07-30 22:49:59 +0000
+++ INSTALL.Unix 2013-08-30 22:06:57 +0000
@@ -3,6 +3,16 @@
33
4A high-level guide to Unix-like systems, inc. Mac OS X and Ubuntu.4A high-level guide to Unix-like systems, inc. Mac OS X and Ubuntu.
55
6Community installation guides are available on the wiki:
7
8 http://wiki.apache.org/couchdb/Installation
9
10This document is the canonical source of installation information. However, many
11systems have gotchas that you need to be aware of. In addition, dependencies
12frequently change as distributions update their archives. If you're running into
13trouble, be sure to check out the wiki. If you have any tips to share, please
14also update the wiki so that others can benefit from your experience.
15
6Troubleshooting16Troubleshooting
7---------------17---------------
818
@@ -25,69 +35,91 @@
2535
26You should have the following installed:36You should have the following installed:
2737
28 * Erlang OTP (>=R12B5) (http://erlang.org/)38 * Erlang OTP (>=R13B04, <R17) (http://erlang.org/)
29 * ICU (http://icu.sourceforge.net/)39 * ICU (http://icu-project.org/)
30 * OpenSSL (http://www.openssl.org/)40 * OpenSSL (http://www.openssl.org/)
31 * Mozilla SpiderMonkey (1.7) (http://www.mozilla.org/js/spidermonkey/)41 * Mozilla SpiderMonkey (1.7) (http://www.mozilla.org/js/spidermonkey/)
32 * GNU Make (http://www.gnu.org/software/make/)42 * GNU Make (http://www.gnu.org/software/make/)
33 * GNU Compiler Collection (http://gcc.gnu.org/)43 * GNU Compiler Collection (http://gcc.gnu.org/)
34 * libcurl (http://curl.haxx.se/libcurl/)44 * libcurl (http://curl.haxx.se/libcurl/)
35 * help2man (http://www.gnu.org/s/help2man/)45 * help2man (http://www.gnu.org/s/help2man/)
46 * Python (>=2.7) for docs (http://python.org/)
47 * Python Sphinx (>=1.1.3) (http://pypi.python.org/pypi/Sphinx)
3648
37It is recommended that you install Erlang OTP R12B-5 or above where possible.49It is recommended that you install Erlang OTP R13B-4 or above where possible.
38You will only need libcurl if you plan to run the JavaScript test suite. And50You will only need libcurl if you plan to run the JavaScript test suite. And
39help2man is only need if you plan on installing the CouchDB man pages.51help2man is only need if you plan on installing the CouchDB man pages.
4052Python and Sphinx are only required for building the online documentation.
41Ubuntu
42~~~~~~
43
44For up to date instructions, please see:
45
46 http://wiki.apache.org/couchdb/Installing_on_Ubuntu
47
48Unfortunately, it seems that installing dependancies on Ubuntu is troublesome.
4953
50Debian-based Systems54Debian-based Systems
51~~~~~~~~~~~~~~~~~~~~55~~~~~~~~~~~~~~~~~~~~
5256
53You can install the build tools by running:57You can install the dependencies by running:
5458
55 sudo apt-get install build-essential59 sudo apt-get install build-essential
5660 sudo apt-get install erlang-base-hipe
57You can install the other dependencies by running:61 sudo apt-get install erlang-dev
5862 sudo apt-get install erlang-manpages
59 sudo apt-get install erlang libicu-dev libmozjs-dev libcurl4-openssl-dev63 sudo apt-get install erlang-eunit
64 sudo apt-get install erlang-nox
65 sudo apt-get install libicu-dev
66 sudo apt-get install libmozjs-dev
67 sudo apt-get install libcurl4-openssl-dev
68 sudo apt-get install pkg-config
69
70There are lots of Erlang packages. If there is a problem with your install, try
71a different mix. There is more information on the wiki. Additionally, you might
72want to install some of the optional Erlang tools which may also be useful.
6073
61Be sure to update the version numbers to match your system's available packages.74Be sure to update the version numbers to match your system's available packages.
6275
76For up to date instructions, please see:
77
78 http://wiki.apache.org/couchdb/Installing_on_Debian
79
80 http://wiki.apache.org/couchdb/Installing_on_Ubuntu
81
82Unfortunately, it seems that installing dependencies on Ubuntu is troublesome.
83
84RedHat-based (Fedora, Centos, RHEL) Systems
85~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
86
87You can install the dependencies by running:
88
89 sudo yum groupinstall "Development Tools"
90 sudo yum install autoconf
91 sudo yum install autoconf-archive
92 sudo yum install automake
93 sudo yum install libtool
94 sudo yum install perl-Test-Harness
95 sudo yum install erlang-etap
96 sudo yum install erlang-erts
97 sudo yum install erlang-os_mon
98 sudo yum install erlang-eunit
99 sudo yum install libicu-devel
100 sudo yum install js-devel
101 sudo yum install curl-devel
102 sudo yum install pkg-config
103
104While CouchDB builds against the default js-devel-1.7.0 included in some
105distributions, it's recommended to use a more recent js-devel-1.8.5.
106
63Mac OS X107Mac OS X
64~~~~~~~~108~~~~~~~~
65109
66You can install the build tools by running:110To build CouchDB from source on Mac OS X, you will need to install Xcode.
67
68 open /Applications/Installers/Xcode\ Tools/XcodeTools.mpkg
69111
70You can install the other dependencies by running:112You can install the other dependencies by running:
71113
72 brew install erlang icu4c spidermonkey curl
73
74You may want to link ICU so that CouchDB can find the header files automatically:
75
76 brew link icu4c
77
78The same is true for recent versions of Erlang:
79
80 brew link erlang
81
82If you are upgrading your version of CouchDB and have an older nspr and
83Spidermonkey installed you may encounter an error during the ./configure step
84below. This is generally due to nspr being installed without its pkg-config
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches