diff --git a/lib/http_tools.sh b/lib/http_tools.sh index 813071c..1b587c4 100755 --- a/lib/http_tools.sh +++ b/lib/http_tools.sh @@ -23,11 +23,12 @@ fi ####################################################################### # -# Given a web resource and a cache, if the resource is cached, request -# the resource using HTTP Conditional GET [RFC 7232], otherwise issue -# an ordinary GET request. In either case, if the server responds with -# 200, cache the resource and return the response body. If the server -# responds with 304, return the cached resource instead. +# Given a web resource and a local cache, if the resource is cached, +# request the resource using HTTP Conditional GET [RFC 7232], otherwise +# issue an ordinary GET request for the resource. In either case, if +# the server responds with 200, cache the resource and return the +# response body. If the server responds with 304, return the cached +# resource instead. # # Usage: conditional_get [-v] [-F | -C] -d CACHE_DIR -t TMP_DIR HTTP_LOCATION # @@ -45,11 +46,12 @@ fi # Use option -F or -C to alter the default behavior of the function. # # Option -F forces the return of a fresh resource, that is, if the -# server responds with 304, an error occurs and the function returns -# with a nonzero return code. +# server responds with 304, the function returns with a nonzero return +# code. # # Option -C causes the function to go directly to cache. No GET request -# is issued. This option is useful in offline mode. +# is issued. (This option is useful in offline mode.) If the resource +# is not cached, the function returns with a nonzero return code. # # The output of the curl command-line tool is stored in the following # temporary files: @@ -62,7 +64,22 @@ fi # # command_paths.sh # -# This library file must be sourced BEFORE calling this function. +# The library file must be sourced BEFORE calling this function. +# +# RETURN CODES +# +# 0: success +# 1: quiet failure mode: +# option -F but no fresh resource available OR +# option -C but no cached resource available +# 2: initialization failure +# 3: unspecified failure +# 4: hash operation failed +# 5: curl failed +# 6: call to get_header_value failed +# 7: call to get_response_code failed +# 8: copy to cache failed +# 9: unexpected HTTP response # # TODO: # - follow redirects? @@ -72,15 +89,16 @@ fi conditional_get () { if ! $COMMAND_PATHS; then - echo "ERROR: global command paths not found" >&2 + echo "ERROR: $FUNCNAME: global command paths not found" >&2 return 2 fi - local script_version="0.6" + local script_version="0.7" local user_agent_string="HTTP Conditional GET client $script_version" local hash local exit_code + local return_code local cached_header_file local cached_content_file local conditional_get_mode @@ -188,8 +206,8 @@ conditional_get () { ) exit_code=$? if [ $exit_code -ne 0 ]; then - echo "ERROR: $FUNCNAME failed to hash the location URL" >&2 - return $exit_code + echo "ERROR: $FUNCNAME failed to hash the location URL (exit code: $exit_code)" >&2 + return 4 fi cached_header_file="$cache_dir/${hash}_headers" @@ -206,14 +224,15 @@ conditional_get () { /bin/cat "$cached_content_file" return 0 fi + conditional_get_mode=true else # ensure cache integrity /bin/rm -f "$cached_header_file" "$cached_content_file" >&2 - if $cache_only_mode; then - echo "ERROR: $FUNCNAME failed to find cached resource: $location" >&2 - return 1 - fi + + # quiet failure mode + $cache_only_mode && return 1 + conditional_get_mode=false fi @@ -260,20 +279,20 @@ conditional_get () { do_conditional_get=false if $conditional_get_mode; then header_value=$( get_header_value "$cached_header_file" 'ETag' ) - exit_code=$? - if [ $exit_code -ne 0 ]; then - echo "ERROR: $FUNCNAME: get_header_value failed to initialize" >&2 - return $exit_code + return_code=$? + if [ $return_code -ne 0 ]; then + echo "ERROR: $FUNCNAME: get_header_value (return code: $return_code)" >&2 + return 6 fi if [ -n "$header_value" ]; then do_conditional_get=true curl_opts="${curl_opts} --header 'If-None-Match: $header_value'" else header_value=$( get_header_value "$cached_header_file" 'Last-Modified' ) - exit_code=$? - if [ $exit_code -ne 0 ]; then - echo "ERROR: $FUNCNAME: get_header_value failed to initialize" >&2 - return $exit_code + return_code=$? + if [ $return_code -ne 0 ]; then + echo "ERROR: $FUNCNAME: get_header_value (return code: $return_code)" >&2 + return 6 fi if [ -n "$header_value" ]; then do_conditional_get=true @@ -288,8 +307,8 @@ conditional_get () { eval $cmd exit_code=$? if [ $exit_code -ne 0 ]; then - echo "ERROR: $FUNCNAME: curl failed ($exit_code)" >&2 - return $exit_code + echo "ERROR: $FUNCNAME: curl failed (exit code: $exit_code)" >&2 + return 5 fi ####################################################################### @@ -304,14 +323,14 @@ conditional_get () { # sanity check if [ ! -f "$tmp_header_file" ]; then echo "ERROR: $FUNCNAME unable to find header file $tmp_header_file" >&2 - return 1 + return 3 fi response_code=$( get_response_code "$tmp_header_file" ) - exit_code=$? - if [ $exit_code -ne 0 ]; then - echo "ERROR: $FUNCNAME: get_response_code failed to initialize" >&2 - return $exit_code + return_code=$? + if [ $return_code -ne 0 ]; then + echo "ERROR: $FUNCNAME: get_response_code failed (return code: $return_code)" >&2 + return 7 fi $verbose_mode && printf "$FUNCNAME received response code: %d\n" "$response_code" >> "$tmp_log_file" @@ -319,10 +338,10 @@ conditional_get () { # sanity check declared_content_length=$( get_header_value "$tmp_header_file" 'Content-Length' ) - exit_code=$? - if [ $exit_code -ne 0 ]; then - echo "ERROR: $FUNCNAME: get_header_value failed to initialize" >&2 - return $exit_code + return_code=$? + if [ $return_code -ne 0 ]; then + echo "ERROR: $FUNCNAME: get_header_value failed (return code: $return_code)" >&2 + return 6 fi actual_content_length=$( /bin/cat "$tmp_content_file" \ | /usr/bin/wc -c \ @@ -331,7 +350,7 @@ conditional_get () { if [ -n "$declared_content_length" ]; then if [ "$declared_content_length" != "$actual_content_length" ]; then echo "ERROR: $FUNCNAME failed content length check" >&2 - return 1 + return 3 fi else echo "WARNING: Content-Length response header missing" >&2 @@ -351,22 +370,25 @@ conditional_get () { exit_code=$? if [ $exit_code -ne 0 ]; then /bin/rm -f "$cached_header_file" "$cached_content_file" >&2 - echo "ERROR: $FUNCNAME failed copy to file $cached_header_file" >&2 - return $exit_code + echo "ERROR: $FUNCNAME failed copy to file $cached_header_file (exit code: $exit_code)" >&2 + return 8 fi /bin/cp -f "$tmp_content_file" "$cached_content_file" >&2 exit_code=$? if [ $exit_code -ne 0 ]; then /bin/rm -f "$cached_header_file" "$cached_content_file" >&2 - echo "ERROR: $FUNCNAME failed copy to file $cached_content_file" >&2 - return $exit_code + echo "ERROR: $FUNCNAME failed copy to file $cached_content_file (exit code: $exit_code)" >&2 + return 8 fi elif [ "$response_code" = "304" ]; then + # quiet failure mode + $force_output_mode && return 1 + $verbose_mode && echo "$FUNCNAME downloaded 0 bytes (cache is up-to-date)" >> "$tmp_log_file" else echo "ERROR: $FUNCNAME failed with HTTP response code $response_code" >&2 - return 1 + return 9 fi ####################################################################### @@ -374,13 +396,8 @@ conditional_get () { # output the resource content # ####################################################################### - - if $force_output_mode && [ "$response_code" = "304" ]; then - echo "ERROR: $FUNCNAME failed to get fresh resource: $location" >&2 - return 1 - fi - /bin/cat "${cached_content_file}" + /bin/cat "$cached_content_file" return 0 }