⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 webserver.c

📁 电驴下载工具eMule0.47aVeryCD的源代码,可作分析测试也可用于P2P软件的开发研究.
💻 C
📖 第 1 页 / 共 4 页
字号:
                if( ( pVirtualDirCallback->
                      get_info( filename->buf, &finfo ) != UPNP_E_SUCCESS )
                    || finfo.is_directory ) {
                    err_code = HTTP_NOT_FOUND;
                    goto error_handler;
                }
            }
            // not readable
            if( !finfo.is_readable ) {
                err_code = HTTP_FORBIDDEN;
                goto error_handler;
            }
            // finally, get content type
            // if ( get_content_type(filename->buf, &content_type) != 0 )
            //{
            //  goto error_handler;
            // }
        }
    } else if( !using_alias ) {
        if( gDocumentRootDir.length == 0 ) {
            goto error_handler;
        }
        //
        // get file name
        //

        // filename str
        if( membuffer_assign_str( filename, gDocumentRootDir.buf ) != 0 ||
            membuffer_append_str( filename, request_doc ) != 0 ) {
            goto error_handler; // out of mem
        }
        // remove trailing slashes
        while( filename->length > 0 &&
               filename->buf[filename->length - 1] == '/' ) {
            membuffer_delete( filename, filename->length - 1, 1 );
        }

        if( req->method != HTTPMETHOD_POST ) {
            // get info on file
            if( get_file_info( filename->buf, &finfo ) != 0 ) {
                err_code = HTTP_NOT_FOUND;
                goto error_handler;
            }
            // try index.html if req is a dir
            if( finfo.is_directory ) {
                if( filename->buf[filename->length - 1] == '/' ) {
                    temp_str = "index.html";
                } else {
                    temp_str = "/index.html";
                }
                if( membuffer_append_str( filename, temp_str ) != 0 ) {
                    goto error_handler;
                }
                // get info
                if( get_file_info( filename->buf, &finfo ) != 0 ||
                    finfo.is_directory ) {
                    err_code = HTTP_NOT_FOUND;
                    goto error_handler;
                }
            }
            // not readable
            if( !finfo.is_readable ) {
                err_code = HTTP_FORBIDDEN;
                goto error_handler;
            }

        }
        // finally, get content type
        //      if ( get_content_type(filename->buf, &content_type) != 0 )
        //      {
        //          goto error_handler;
        //      }
    }

    RespInstr->ReadSendSize = finfo.file_length;

    //Check other header field.
    if( ( err_code =
          CheckOtherHTTPHeaders( req, RespInstr,
                                 finfo.file_length ) ) != HTTP_OK ) {
        goto error_handler;
    }

    if( req->method == HTTPMETHOD_POST ) {
        *rtype = RESP_POST;
        err_code = UPNP_E_SUCCESS;
        goto error_handler;
    }

    if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) {
        //Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT
        //Transfer-Encoding: chunked
        // K means add chunky header ang G means range header.
        if( http_MakeMessage( headers, resp_major, resp_minor, "RTGKDstcSCc", HTTP_PARTIAL_CONTENT, // status code
                              // RespInstr->ReadSendSize,// content length
                              finfo.content_type,
                              //     content_type.buf,            // content type
                              RespInstr,    // Range
                              "LAST-MODIFIED: ",
                              &finfo.last_modified ) != 0 ) {
            goto error_handler;
        }
    } else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) {

        //Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT
        //Transfer-Encoding: chunked
        // K means add chunky header ang G means range header.
        if( http_MakeMessage( headers, resp_major, resp_minor, "RNTGDstcSCc", HTTP_PARTIAL_CONTENT, // status code
                              RespInstr->ReadSendSize,  // content length
                              finfo.content_type,
                              //content_type.buf,            // content type
                              RespInstr,    //Range Info
                              "LAST-MODIFIED: ",
                              &finfo.last_modified ) != 0 ) {
            goto error_handler;
        }

    } else if( !RespInstr->IsRangeActive && RespInstr->IsChunkActive ) {

        //Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT
        //Transfer-Encoding: chunked
        // K means add chunky header ang G means range header.
        if( http_MakeMessage( headers, resp_major, resp_minor, "RKTDstcSCc", HTTP_OK,   // status code
                              //RespInstr->ReadSendSize,// content length
                              finfo.content_type,
                              // content_type.buf,            // content type
                              "LAST-MODIFIED: ",
                              &finfo.last_modified ) != 0 ) {
            goto error_handler;
        }

    } else {
        if( RespInstr->ReadSendSize >= 0 ) {
            //Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT
            //Transfer-Encoding: chunked
            // K means add chunky header ang G means range header.
            if( http_MakeMessage( headers, resp_major, resp_minor, "RNTDstcSCc", HTTP_OK,   // status code
                                  RespInstr->ReadSendSize,  // content length
                                  finfo.content_type,
                                  //content_type.buf,          // content type
                                  "LAST-MODIFIED: ",
                                  &finfo.last_modified ) != 0 ) {
                goto error_handler;
            }
        } else {
            //Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT
            //Transfer-Encoding: chunked
            // K means add chunky header ang G means range header.
            if( http_MakeMessage( headers, resp_major, resp_minor, "RTDstcSCc", HTTP_OK,    // status code
                                  //RespInstr->ReadSendSize,// content length
                                  finfo.content_type,
                                  //content_type.buf,          // content type
                                  "LAST-MODIFIED: ",
                                  &finfo.last_modified ) != 0 ) {
                goto error_handler;
            }
        }
    }

    if( req->method == HTTPMETHOD_HEAD ) {
        *rtype = RESP_HEADERS;
    } else if( using_alias ) {
        // GET xml
        *rtype = RESP_XMLDOC;
    } else if( using_virtual_dir ) {
        *rtype = RESP_WEBDOC;
    } else {
        // GET filename
        *rtype = RESP_FILEDOC;
    }

    //simple get http 0.9 as specified in http 1.0
    //don't send headers
    if( req->method == HTTPMETHOD_SIMPLEGET ) {
        membuffer_destroy( headers );
    }

    err_code = UPNP_E_SUCCESS;

  error_handler:
    free( request_doc );
    ixmlFreeDOMString( finfo.content_type );
    //  membuffer_destroy( &content_type );
    if( err_code != UPNP_E_SUCCESS && alias_grabbed ) {
        alias_release( alias );
    }

    return err_code;
}

/************************************************************************
* Function: http_RecvPostMessage										
*																		
* Parameters:															
*	http_parser_t* parser ; HTTP Parser object							
*	IN SOCKINFO *info ; Socket Information object													
*	char * filename ; 	File where received data is copied to
*	struct SendInstruction * Instr	; Send Instruction object which gives
*			information whether the file is a virtual file or not.
*																		
* Description: Receives the HTTP post message														
*																		
* Returns:																
*	HTTP_INTERNAL_SERVER_ERROR											
*	HTTP_UNAUTHORIZED													
*	HTTP_REQUEST_RANGE_NOT_SATISFIABLE									
*	HTTP_OK																
************************************************************************/
int
http_RecvPostMessage( http_parser_t * parser,
                      IN SOCKINFO * info,
                      char *filename,
                      struct SendInstruction *Instr )
{

    unsigned int Data_Buf_Size = 1024;
    char Buf[1024];
    int Timeout = 0;
    long Num_Write = 0;
    FILE *Fp;
    parse_status_t status = PARSE_OK;
    xboolean ok_on_close = FALSE;
    unsigned int entity_offset = 0;
    int num_read = 0;
    int ret_code = 0;

    if( Instr && Instr->IsVirtualFile ) {

        Fp = virtualDirCallback.open( filename, UPNP_WRITE );
        if( Fp == NULL ) {
            return HTTP_INTERNAL_SERVER_ERROR;
        }

    } else {
        Fp = fopen( filename, "wb" );
        if( Fp == NULL ) {
            return HTTP_UNAUTHORIZED;
        }
    }

    parser->position = POS_ENTITY;

    do {
        //first parse what has already been gotten
        if( parser->position != POS_COMPLETE ) {
            status = parser_parse_entity( parser );
        }

        if( status == PARSE_INCOMPLETE_ENTITY ) {
            // read until close
            ok_on_close = TRUE;
        } else if( ( status != PARSE_SUCCESS )
                   && ( status != PARSE_CONTINUE_1 )
                   && ( status != PARSE_INCOMPLETE ) ) {
            //error
            return HTTP_BAD_REQUEST;
        }
        //read more if necessary entity
        while( ( ( entity_offset + Data_Buf_Size ) >
                 parser->msg.entity.length )
               && ( parser->position != POS_COMPLETE ) ) {
            num_read = sock_read( info, Buf, sizeof( Buf ), &Timeout );
            if( num_read > 0 ) {
                // append data to buffer
                ret_code = membuffer_append( &parser->msg.msg,
                                             Buf, num_read );
                if( ret_code != 0 ) {
                    // set failure status
                    parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
                    return HTTP_INTERNAL_SERVER_ERROR;
                }
                status = parser_parse_entity( parser );
                if( status == PARSE_INCOMPLETE_ENTITY ) {
                    // read until close
                    ok_on_close = TRUE;
                } else if( ( status != PARSE_SUCCESS )
                           && ( status != PARSE_CONTINUE_1 )
                           && ( status != PARSE_INCOMPLETE ) ) {
                    return HTTP_BAD_REQUEST;
                }
            } else if( num_read == 0 ) {
                if( ok_on_close ) {
                    DBGONLY( UpnpPrintf
                             ( UPNP_INFO, HTTP, __FILE__, __LINE__,
                               "<<< (RECVD) <<<\n%s\n-----------------\n",
                               parser->msg.msg.buf );
                             //print_http_headers( &parser->msg );
                         )

                        parser->position = POS_COMPLETE;
                } else {
                    // partial msg
                    parser->http_error_code = HTTP_BAD_REQUEST; // or response
                    return HTTP_BAD_REQUEST;
                }
            } else {
                return num_read;
            }
        }

        if( ( entity_offset + Data_Buf_Size ) > parser->msg.entity.length ) {
            Data_Buf_Size = parser->msg.entity.length - entity_offset;
        }

        memcpy( Buf, &parser->msg.msg.buf[parser->entity_start_position
                                          + entity_offset],
                Data_Buf_Size );
        entity_offset += Data_Buf_Size;

        if( Instr->IsVirtualFile ) {
            Num_Write = virtualDirCallback.write( Fp, Buf, Data_Buf_Size );
            if( Num_Write < 0 ) {
                virtualDirCallback.close( Fp );
                return HTTP_INTERNAL_SERVER_ERROR;
            }
        } else {
            Num_Write = fwrite( Buf, 1, Data_Buf_Size, Fp );
            if( Num_Write < 0 ) {
                fclose( Fp );
                return HTTP_INTERNAL_SERVER_ERROR;
            }
        }

    } while( ( parser->position != POS_COMPLETE )
             || ( entity_offset != parser->msg.entity.length ) );

    if( Instr->IsVirtualFile ) {
        virtualDirCallback.close( Fp );
    } else {
        fclose( Fp );
    }

    /*
       while(TotalByteReceived < Instr->RecvWriteSize &&
       (NumReceived = sock_read(info,Buf, Data_Buf_Size,&Timeout) ) > 0 ) 
       {
       TotalByteReceived = TotalByteReceived + NumReceived;
       Num_Write = virtualDirCallback.write(Fp, Buf, NumReceived);
       if (ferror(Fp))
       {
       virtualDirCallback.close(Fp);
       return HTTP_INTERNAL_SERVER_ERROR;
       }
       }

       if(TotalByteReceived < Instr->RecvWriteSize)
       {
       return HTTP_INTERNAL_SERVER_ERROR;
       }

       virtualDirCallback.close(Fp);
       }
     */
    return HTTP_OK;
}

/************************************************************************
* Function: web_server_callback											
*																		
* Parameters:															
*	IN http_parser_t *parser ; HTTP Parser Object						
*	INOUT http_message_t* req ; HTTP Message request										
*	IN SOCKINFO *info ;			Socket information object													
*																		
* Description: main entry point into web server;						
*	handles HTTP GET and HEAD requests									
*																		
* Returns:																
*	void																
************************************************************************/
void
web_server_callback( IN http_parser_t * parser,
                     INOUT http_message_t * req,
                     IN SOCKINFO * info )
{
    int ret;
    int timeout = 0;
    enum resp_type rtype;
    membuffer headers;
    membuffer filename;
    struct xml_alias_t xmldoc;
    struct SendInstruction RespInstr;

    //Initialize instruction header.
    RespInstr.IsVirtualFile = 0;
    RespInstr.IsChunkActive = 0;
    RespInstr.IsRangeActive = 0;
    RespInstr.IsTrailers = 0;
    // init
    membuffer_init( &headers );
    membuffer_init( &filename );

    //Process request should create the different kind of header depending on the
    //the type of request.
    ret =
        process_request( req, &rtype, &headers, &filename, &xmldoc,
                         &RespInstr );
    if( ret != UPNP_E_SUCCESS ) {
        // send error code
        http_SendStatusResponse( info, ret, req->major_version,
                                 req->minor_version );
    } else {
        //
        // send response
        switch ( rtype ) {
            case RESP_FILEDOC: // send file, I = further instruction to send data.
                http_SendMessage( info, &timeout, "Ibf", &RespInstr,
                                  headers.buf, headers.length,
                                  filename.buf );
                break;

            case RESP_XMLDOC:  // send xmldoc , I = further instruction to send data.
                http_SendMessage( info, &timeout, "Ibb", &RespInstr,
                                  headers.buf, headers.length,
                                  xmldoc.doc.buf, xmldoc.doc.length );
                alias_release( &xmldoc );
                break;

            case RESP_WEBDOC:  //, I = further instruction to send data.
                /*
                   http_SendVirtualDirDoc( info, &timeout, "Ibf",&RespInstr,
                   headers.buf, headers.length,
                   filename.buf );  
                 */
                http_SendMessage( info, &timeout, "Ibf", &RespInstr,
                                  headers.buf, headers.length,
                                  filename.buf );
                break;

            case RESP_HEADERS: // headers only
                http_SendMessage( info, &timeout, "b",
                                  headers.buf, headers.length );

                break;
            case RESP_POST:    // headers only
                ret =
                    http_RecvPostMessage( parser, info, filename.buf,
                                          &RespInstr );
                //Send response.
                http_MakeMessage( &headers, 1, 1, "RTDSCc", ret,
                                  "text/html" );
                http_SendMessage( info, &timeout, "b", headers.buf,
                                  headers.length );
                break;

            default:
                assert( 0 );
        }
    }

    DBGONLY( UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
                         "webserver: request processed...\n" );
         )

        membuffer_destroy( &headers );
    membuffer_destroy( &filename );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -