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

📄 urlbreaker.c

📁 C编写的用来实现search engine的推荐功能
💻 C
字号:
/**
 * URL分析,URL的格式
 *          http://[user[:passwd]@]<host>[:[<port>]][/<path_to_file>[?<query>]]
 * Xu Lubing
 * Nov. 22, 2002
 */

#include "urlbreaker.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#if !__GNUC__
#include <malloc.h>
#endif
#ifdef WIN32
#define strncasecmp _strnicmp
#endif

#define DEFAULT_PORT 80

#define HTTP_HEADING "http://"
#define DEFAULT_FILE "/"
#define HTTP_HEADING_LEN   7 /*= strlen(HTTP_HEADING);*/
#define DEFAULT_FILE_LEN   1 /* = strlen(DEFAULT_FILE); */

/* 错误代码定义 */
typedef enum {
	NO_ERROR = 0,
	NO_URL,
	NO_URLINFO,
	MEM_ERROR,
	UNSUPPORTED_PROTOCOL,
	HOST_EXPECTED,
	BAD_HOST_FORMAT,
	BAD_PORT_FORMAT
} ERROR_CODE;

/* 错误原因定义 */
static const char* ERROR_MESSAGE[] = {
	NULL,
	"给定的URL为NULL",
	"urlInfo为NULL",
	"申请内存失败",
	"协议部分必须以\"http://\"打头",
	"缺少主机部分",
	"主机部分格式错误",
	"端口号必须是数字"
};

/**
 * 分析URL
 * IN:
 *   url:     给定的URL
 *   urlInfo: 存放结果。变量请事先定义,调用函数时会进行初始化
 * OUT:
 *   NULL: 分析成功
 *   非空: 分析失败,返回的是错误原因
 */
const char* parseURL(const char* url, URLINFO* urlInfo)
{
	ERROR_CODE errno = NO_ERROR;
	int urlLen;
	char* p;
	int hasPort = 0; /*是否有端口号标志*/
	
	/* 检查输入 */
	if (urlInfo == NULL)
	{
		errno = NO_URLINFO;
		goto EXIT;
	}
	memset(urlInfo, 0, sizeof(URLINFO)); /* 初始化 */
	
	if (url == NULL)
	{
		errno = NO_URL;
		goto EXIT;
	}
	
	
	urlLen = strlen(url);
	urlInfo->tmpbuf = (char*)malloc(urlLen + 1 + DEFAULT_FILE_LEN + 1);
	if (urlInfo->tmpbuf == NULL) {
		errno = MEM_ERROR;
		goto EXIT;
	}
	strcpy(urlInfo->tmpbuf, url);
	
	urlInfo->port = DEFAULT_PORT;
	
	/*比较协议部分*/
	if (strncasecmp(urlInfo->tmpbuf, HTTP_HEADING, HTTP_HEADING_LEN) != 0)
	{
		errno = UNSUPPORTED_PROTOCOL;
		goto EXIT;
	}
	
	/* 取认证部分 */
	urlInfo->user = urlInfo->tmpbuf+HTTP_HEADING_LEN;
	p = strchr(urlInfo->user, '@');
	if (p != NULL)
	{
		char* pTest;
		
		*p = '\0'; /* 临时设为字符串结尾 */
		pTest = strchr(urlInfo->user, '/');
		if (pTest != NULL)
		{
			/* '@'在'/'后,不是用户认证信息,恢复'@' */
			*p = '@';
			urlInfo->user = NULL;
		}
		else
		{
			/* 认为有认证信息,找口令与用户名的分隔符 */
			pTest = strchr(urlInfo->user, ':');
			if (pTest != NULL)
			{
				*pTest = '\0';
				urlInfo->passwd = pTest+1;
			}
			urlInfo->host = p+1; /* 主机起始位置确定 */
		}
	}
	else
	{
		urlInfo->user = NULL;
	}
	
	/*取主机部分*/
	if (urlInfo->user == NULL)
	{
		urlInfo->host = urlInfo->tmpbuf + HTTP_HEADING_LEN;
	}
	
	/*主机部分必须有字符且不能以'.'打头*/
	if (urlInfo->host[0] == '\0')
	{
		errno = HOST_EXPECTED;
		goto EXIT;
	}
	if (urlInfo->host[0] == '.')
	{
		errno = BAD_HOST_FORMAT;
		goto EXIT;
	}
	for (p=(char*)(urlInfo->host); (*p!='\0' && *p!='/' && *p!=':'); p++);
	
	/*主机部分不能以'.'结束*/
	if (*(p-1) == '.')
	{
		errno = BAD_HOST_FORMAT;
		goto EXIT;
	}
	
	switch (*p)
	{
	case '\0':
		/*整个分析结束,复制缺省文件名*/
		urlInfo->file = DEFAULT_FILE;
		goto EXIT;
		
	case ':':
		/*有端口号*/
		hasPort = 1;
		break;
		
	case '/':
		/*文件开始*/
		break;
	}
	*p++ = '\0'; /*字符串结束标志*/
	
	/*取端口号*/
	if (hasPort)
	{
		if (isdigit(*p))
		{
			urlInfo->port = atoi(p);
			
			/*跳过所有的数字*/
			for (; (*p != '\0') && isdigit(*p); p++);
		}
		
		/*如果后面仍有字符,必须是'/'*/
		if (*p != '\0' && *p != '/')
		{
			errno = BAD_PORT_FORMAT;
			goto EXIT;
		}
		
		/*处理文件*/
		if (*p == '/')
		{
			urlInfo->file = p;
		}
		else
		{
			urlInfo->file = DEFAULT_FILE;
		}
		
		goto GETQUERY;
	}
	
	/*取文件*/
	urlInfo->file = p; /*设置指针头部*/
	p = urlInfo->tmpbuf + urlLen;
	while (p >= urlInfo->file)
	{
		*(p+1) = *p;
		p--;
	}
	*((char*)(urlInfo->file)) = '/';
	
GETQUERY:
	/* 取query */
	urlInfo->query = strchr(urlInfo->file, '?');
	if (urlInfo->query != NULL)
	{
		urlInfo->query++;
	}
	
EXIT:
	if (errno != NO_ERROR)
	{
		/* 如果有错误,释放分配的空间 */
		freeURLInfo(urlInfo);
	}
	
	return ERROR_MESSAGE[errno];
}

/**
 * 释放结果中的动态空间
 * IN:
 *   urlInfo: 存放结果的结果。
 */
void freeURLInfo(URLINFO* urlInfo)
{
	if (urlInfo != NULL && urlInfo->tmpbuf != NULL)
	{
		free(urlInfo->tmpbuf);
		urlInfo->tmpbuf = NULL;
	}
}

/**
 * 输出分析结果,仅用于测试
 * IN:
 *   urlInfo: 存放结果的结果。
 *   out:     文件指针,如stdout
 */
void dumpURLInfo(URLINFO* urlInfo, FILE* out)
{
	if (urlInfo == NULL || urlInfo->tmpbuf == NULL || out == NULL)
	{
		return;
	}
	
	fprintf(out, "host: %s\n"
				 "port: %d\n"
				 "file: %s\n"
				 "query: %s\n"
				 "user: %s\n"
				 "passwd: %s\n",
				 (urlInfo->host != NULL ? urlInfo->host : "[no host]"),
				 urlInfo->port,
				 (urlInfo->file != NULL ? urlInfo->file : "[no file]"),
				 (urlInfo->query != NULL ? urlInfo->query : "[no query]"),
				 (urlInfo->user != NULL ? urlInfo->user : "[no user]"),
				 (urlInfo->passwd != NULL ? urlInfo->passwd : "[no passwd]")
			);
}

⌨️ 快捷键说明

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