// Multicast packet.
static apr_status_t multicast_packet(request_rec* rec, multicast_conf* conf, const char* _msg)
{
  int r, s = socket(AF_INET, SOCK_DGRAM, 0);
  char* msg = unescape_specialchars(rec->pool, _msg);

  AP_LOG_DEBUG(rec, "unescaped string: %s", msg);

  r = setsockopt(s, SOL_IP, IP_MULTICAST_IF, conf->multicast_interface.addr, conf->multicast_interface.len);
  if(r!=0) {
    r = errno;
    AP_LOG_ERR(rec, "setsockopt() failed - %s(%d)", strerror(r), r);
    goto FINALLY;
  }

  r = connect(s, conf->multicast_address.addr, conf->multicast_address.len);
  if(r!=0) {
    r = errno;
    AP_LOG_ERR(rec, "connect() failed - %s(%d)", strerror(r), r);
    goto FINALLY;
  }

  r = send(s, msg, strlen(msg), 0);
  r = (r>=0)? APR_SUCCESS: errno;

FINALLY:
  if(s>=0) {
    shutdown(s, SHUT_RDWR);
    close(s);
  }
  return r;
}
//
// Output filter.
//
static apr_status_t resize_output_filter(ap_filter_t* f, apr_bucket_brigade* in_bb)
{
  request_rec* rec =f->r;
  resize_conf* conf = (resize_conf*)ap_get_module_config(rec->per_dir_config, &resizeimage_module);
  const char* content_type, *target_type = "JPEG";
  const char* image_url, *resize_param, *image_hash=NULL;
  Magick::Blob blob;
  char* vlob = NULL;
  size_t vlob_length = 0;
  int cache_hit = FALSE;

  AP_LOG_VERBOSE(rec, "Incoming %s.", __FUNCTION__);

  // Pass thru by request types.
  if(rec->status!=HTTP_OK || rec->main!=NULL || rec->header_only
    || (rec->handler!= NULL && strcmp(rec->handler, "default-handler") == 0)) goto PASS_THRU;

  AP_LOG_VERBOSE(rec, "-- Checking responce headers.");

  // Obtain and erase x-resize-image header or pass through.
  image_url = get_and_unset_header(rec->headers_out, X_RESIZE);
  if(image_url== NULL || image_url[0]=='\0') {
    image_url = get_and_unset_header(rec->err_headers_out, X_RESIZE);
  }
  if(image_url==NULL || image_url[0]=='\0') goto PASS_THRU;

  // Check content-type
  content_type = rec->content_type;
  if(content_type) {
    if(strcasecmp(content_type, "image/jpeg")==0) {
      target_type = "JPEG";
    } else
    if(strcasecmp(content_type, "image/png")==0) {
      target_type = "PNG";
    } else
    if(strcasecmp(content_type, "image/gif")==0) {
      target_type = "GIF";
    } else goto PASS_THRU;
  }

  // Resize parameter
  resize_param = get_and_unset_header(rec->headers_out, X_RESIZE_PARAM);
  if(resize_param==NULL || resize_param[0]=='\0') {
    resize_param = get_and_unset_header(rec->err_headers_out, X_RESIZE_PARAM);
  }
  if(resize_param[0]=='\0') resize_param = NULL;

  // Image hash
  image_hash = get_and_unset_header(rec->headers_out, X_RESIZE_HASH);
  if(image_hash==NULL || image_hash[0]=='\0') {
    image_hash = get_and_unset_header(rec->err_headers_out, X_RESIZE_HASH);
  }
 
  // Open image and resize.
  AP_LOG_INFO(rec, "URL: %s, %s => %s (%s)", image_url, content_type, resize_param, image_hash);

  if(image_hash) {
    // Try memcached...
    image_hash = apr_psprintf(rec->pool, "%s:%s:%s", image_hash, target_type, resize_param);
    memcached_return r;
    uint32_t flags;
    vlob = memcached_get(conf->memc, image_hash, strlen(image_hash), &vlob_length, &flags, &r);
    if(r==MEMCACHED_SUCCESS) {
      AP_LOG_DEBUG(rec, "Restored from memcached: %s, len=%d", image_hash, vlob_length);
      cache_hit = TRUE;
      goto WRITE_DATA;
    } else {
      AP_LOG_DEBUG(rec, "Can't restore from memcached: %s - %s(%d)", image_hash, memcached_strerror(conf->memc, r), r);
    }
  }

  // Reszize
  try {
    Magick::Image image;

    image.read(image_url);
    if(resize_param) image.zoom(resize_param);
    image.magick(target_type);
    image.quality(conf->jpeg_quality);
    image.write(&blob);
    vlob = (char*)blob.data();
    vlob_length = blob.length();
  }
  catch(Magick::Exception& err) {
    AP_LOG_ERR(rec, __FILE__ ": Magick failed: %s", err.what());
    goto PASS_THRU;
  }

  if(image_hash) {
    // Store to memcached...
    memcached_return r = memcached_set(conf->memc, image_hash, strlen(image_hash), vlob, vlob_length, conf->expire, 0);
    if(r==MEMCACHED_SUCCESS) {
      AP_LOG_DEBUG(rec, "Stored to memcached: %s(len=%d)", image_hash, vlob_length);
    } else {
      AP_LOG_DEBUG(rec, "Can't store from memcached: %s(len=%d) - %s(%d)", image_hash, vlob_length,memcached_strerror(conf->memc, r), r);
    }
  }

WRITE_DATA:
  AP_LOG_VERBOSE(rec, "-- Creating resize buckets.");

  // Drop all content and headers related.
  while(!APR_BRIGADE_EMPTY(in_bb)) {
    apr_bucket* b = APR_BRIGADE_FIRST(in_bb);
    apr_bucket_delete(b);
  }
  rec->eos_sent = 0;
  rec->clength = 0;
  unset_header(rec, "Content-Length");
  unset_header(rec, "Content-Encoding");
  unset_header(rec, "Last-Modified");
  unset_header(rec, "ETag");

  // Start resize bucket.
  {
    apr_off_t remain = vlob_length, offset = 0;
    while(remain>0) {
      apr_off_t bs = (remain<AP_MAX_SENDFILE)? remain: AP_MAX_SENDFILE;
      char* heap = (char*)malloc(bs);
      memcpy(heap, vlob+offset, bs);
      apr_bucket* b = apr_bucket_heap_create(heap, bs, free, in_bb-> bucket_alloc);
      APR_BRIGADE_INSERT_TAIL(in_bb, b);
      remain -= bs;
      offset += bs;
    }
    APR_BRIGADE_INSERT_TAIL(in_bb, apr_bucket_eos_create(in_bb->bucket_alloc));
    ap_set_content_length(rec, vlob_length);
    if(cache_hit) free(vlob);
  }
  AP_LOG_VERBOSE(rec, "-- Create done.");
 
PASS_THRU:
  AP_LOG_VERBOSE(rec, "-- Filter done.");
  ap_remove_output_filter(f);
  return ap_pass_brigade(f->next, in_bb);
}
Exemplo n.º 3
0
//
// Output filter.
//
static apr_status_t reproxy_output_filter(ap_filter_t* f, apr_bucket_brigade* in_bb)
{
    request_rec* rec =f->r;
    const char* reproxy_url;

    AP_LOG_VERBOSE(rec, "Incoming %s.", __FUNCTION__);

    // Pass thru by request types.
    if(rec->status!=HTTP_OK || rec->main!=NULL || rec->header_only
            || (rec->handler!= NULL && strcmp(rec->handler, "default-handler") == 0)) goto PASS_THRU;

    AP_LOG_VERBOSE(rec, "-- Checking responce headers.");

    // Obtain and erase x-reproxy-url header or pass through.
    reproxy_url = get_and_unset_header(rec->headers_out, X_REPROXY);
    if(reproxy_url== NULL || reproxy_url[0]=='\0') {
        reproxy_url = get_and_unset_header(rec->err_headers_out, X_REPROXY);
    }
    if(reproxy_url==NULL || reproxy_url[0]=='\0') goto PASS_THRU;


    AP_LOG_VERBOSE(rec, "-- Creating reproxy buckets.");

    // Drop all content and headers related.
    while(!APR_BRIGADE_EMPTY(in_bb)) {
        apr_bucket* b = APR_BRIGADE_FIRST(in_bb);
        apr_bucket_delete(b);
    }
    rec->eos_sent = 0;
    rec->clength = 0;
    unset_header(rec, "Content-Length");
    //unset_header(rec, "Content-Type");
    unset_header(rec, "Content-Encoding");
    unset_header(rec, "Last-Modified");
    unset_header(rec, "ETag");


    // Start reproxy bucket.
    {
        apr_off_t content_length = 0;
        apr_bucket* b = curl_bucket_create(reproxy_url, content_length, in_bb->bucket_alloc, rec);
        if(b) {
            APR_BRIGADE_INSERT_TAIL(in_bb, b);
            while(content_length>0) {
                AP_LOG_VERBOSE(rec, "  curl_next_bucket_create(b, %llu)", content_length);
                APR_BRIGADE_INSERT_TAIL(in_bb, curl_next_bucket_create(b, content_length));
            }
            APR_BRIGADE_INSERT_TAIL(in_bb, curl_end_bucket_create(b));
            APR_BRIGADE_INSERT_TAIL(in_bb, apr_bucket_eos_create(in_bb->bucket_alloc));
        } else {
            AP_LOG_ERR(rec, "curl_bucket_create() failed - %d", rec->status);
            ap_send_error_response(rec, rec->status);
        }
    }
    AP_LOG_VERBOSE(rec, "-- Create done.");


PASS_THRU:
    AP_LOG_VERBOSE(rec, "-- Filter done.");
    ap_remove_output_filter(f);
    return ap_pass_brigade(f->next, in_bb);
}