示例#1
0
void t01_test_mime(){
	INIT_LOCAL();
	
	FAIL_IF_NOT_EQUAL_STR("text/plain", onion_mime_get("txt"));
	FAIL_IF_NOT_EQUAL_STR("text/plain", onion_mime_get("fdsfds"));
	FAIL_IF_NOT_EQUAL_STR("text/html", onion_mime_get("html"));
	FAIL_IF_NOT_EQUAL_STR("image/png", onion_mime_get("file.png"));
	FAIL_IF_NOT_EQUAL_STR("application/javascript", onion_mime_get("js"));

	
	onion_mime_set(NULL);
	END_LOCAL();
}
示例#2
0
文件: opack.c 项目: davidmoreno/onion
/**
 * @short Generates the necesary data to the output stream.
 */
void parse_file(const char *prefix, const char *filename, FILE * outfd,
                onion_assets_file * assets) {
  FILE *fd = fopen(filename, "r");
  if (!fd) {
    fprintf(stderr, "ERROR: Cant open file %s: ", filename);
    perror("");
    onion_assets_file_free(assets);
    exit(3);
  }
  char *fname = funcname(prefix, basename((char *)filename));
  char buffer[4096];
  buffer[4095] = 0;

  snprintf(buffer, sizeof(buffer) - 1,
           "onion_connection_status %s(void *_, onion_request *req, onion_response *res);",
           fname);

  onion_assets_file_update(assets, buffer);

  fprintf(stderr, "Parsing: %s to '%s'.\n", filename, buffer);
  fprintf(outfd,
          "onion_connection_status %s(void *_, onion_request *req, onion_response *res){\n  static const char data[]={\n",
          fname);
  int r, i, l = 0;
  while ((r = fread(buffer, 1, sizeof(buffer) - 1, fd)) != 0) {
    for (i = 0; i < r; i++) {
      fprintf(outfd, "0x%02X, ", buffer[i] & 0x0FF);
      if ((i % 16) == 15) {
        fprintf(outfd, "\n");
      }
    }
    l += r;
  }
  fprintf(outfd, "};\n");

  const char *mime_type = onion_mime_get(filename);
  fprintf(outfd, "  onion_response_set_length(res, %d);\n", l);
  fprintf(outfd,
          "  onion_response_set_header(res, \"Content-Type\", \"%s\");\n",
          mime_type);
  fprintf(outfd,
          "  return onion_response_write(res, data, sizeof(data));\n}\n\n");

  fprintf(outfd, "const unsigned int %s_length = %d;\n\n", fname, l);

  fclose(fd);
  free(fname);
}
示例#3
0
/**
 * @short This shortcut returns the given file contents. 
 * 
 * It sets all the compilant headers (TODO), cache and so on.
 * 
 * This is the recomended way to send static files; it even can use sendfile Linux call 
 * if suitable (TODO).
 * 
 * It does no security checks, so caller must be security aware.
 */
onion_connection_status onion_shortcut_response_file(const char *filename, onion_request *request, onion_response *res){
	int fd=open(filename,O_RDONLY|O_CLOEXEC);
	
	if (fd<0)
		return OCS_NOT_PROCESSED;

	if(O_CLOEXEC == 0) { // Good compiler know how to cut this out
		int flags=fcntl(fd, F_GETFD);
		if (flags==-1){
			ONION_ERROR("Retrieving flags from file descriptor");
		}
		flags|=FD_CLOEXEC;
		if (fcntl(fd, F_SETFD, flags)==-1){
			ONION_ERROR("Setting O_CLOEXEC to file descriptor");
		}
	}
	
	struct stat st;
	if (stat(filename, &st)!=0){
		ONION_WARNING("File does not exist: %s",filename);
		close(fd);
		return OCS_NOT_PROCESSED;
	}
	
	if (S_ISDIR(st.st_mode)){
		close(fd);
		return OCS_NOT_PROCESSED;
	}
	
	size_t length=st.st_size;
	
	char etag[64];
	onion_shortcut_etag(&st, etag);
		
	const char *range=onion_request_get_header(request, "Range");
	if (range){
		strncat(etag,range,sizeof(etag)-1);
	}
	onion_response_set_header(res, "Etag", etag);
	
	if (range && strncmp(range,"bytes=",6)==0){
		onion_response_set_code(res, HTTP_PARTIAL_CONTENT);
		//ONION_DEBUG("Need just a range: %s",range);
		char tmp[1024];
		strncpy(tmp, range+6, 1024);
		char *start=tmp;
		char *end=tmp;
		while (*end!='-' && *end) end++;
		if (*end=='-'){
			*end='\0';
			end++;
			
			//ONION_DEBUG("Start %s, end %s",start,end);
			size_t ends, starts;
			if (*end)
				ends=atol(end);
			else
				ends=length;
			starts=atol(start);
			length=ends-starts+1;
			lseek(fd, starts, SEEK_SET);
			snprintf(tmp,sizeof(tmp),"bytes %d-%d/%d",(unsigned int)starts, (unsigned int)ends, (unsigned int)st.st_size);
			//onion_response_set_header(res, "Accept-Ranges","bytes");
			onion_response_set_header(res, "Content-Range",tmp);
		}
	}
	
	onion_response_set_length(res, length);
	onion_response_set_header(res, "Content-Type", onion_mime_get(filename) );
	ONION_DEBUG("Mime type is %s",onion_mime_get(filename));

  ONION_DEBUG0("Etag %s", etag);
  const char *prev_etag=onion_request_get_header(request, "If-None-Match");
  if (prev_etag && (strcmp(prev_etag, etag)==0)){
    ONION_DEBUG0("Not modified");
    onion_response_set_length(res, 0);
    onion_response_set_code(res, HTTP_NOT_MODIFIED);
    onion_response_write_headers(res);
    close(fd);
    return OCS_PROCESSED;
  }
	onion_response_write_headers(res);
	if ((onion_request_get_flags(request)&OR_HEAD) == OR_HEAD){ // Just head.
		length=0;
	}
	
	if (length){
#ifdef USE_SENDFILE
		if (request->connection.listen_point->write==(void*)onion_http_write){ // Lets have a house party! I can use sendfile!
			onion_response_write(res,NULL,0);
			ONION_DEBUG("Using sendfile");
			int r=sendfile(request->connection.fd, fd, NULL, length);
			ONION_DEBUG("Wrote %d, should be %d (%s)", r, length, r==length ? "ok" : "nok");
			if (r!=length || r<0){
				ONION_ERROR("Could not send all file (%s)", strerror(errno));
				close(fd);
				return OCS_INTERNAL_ERROR;
			}
			res->sent_bytes+=length;
			res->sent_bytes_total+=length;
		}
		else
#endif
		{ // Ok, no I cant, do it as always.
			int r=0,w;
			size_t tr=0;
			char tmp[4046];
			if (length>sizeof(tmp)){
				size_t max=length-sizeof(tmp);
				while( tr<max ){
					r=read(fd,tmp,sizeof(tmp));
					tr+=r;
					if (r<0)
						break;
					w=onion_response_write(res, tmp, r);
					if (w!=r){
						ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r);
						break;
					}
				}
			}
			if (sizeof(tmp) >= (length-tr)){
				r=read(fd, tmp, length-tr);
				w=onion_response_write(res, tmp, r);
				if (w!=r){
					ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r);
				}
			}
		}
	}
	close(fd);
	return OCS_PROCESSED;
}