Example #1
0
// **************************************************************************
// HTTPヘッダを受信して解析する。
//
// 処理するのはGETのみ。GET以外のメソッドが来たらエラー
// 今のところ、URIとuser_agent、Range、Hostを解析。
// URIは、URIデコードもやる。
//
//	return: 0 		正常終了
//	return: 0以外 	エラー
// **************************************************************************
static int http_header_receive(int accept_socket, HTTP_RECV_INFO *http_recv_info_p)
{
	int result = 0;
	int	recv_len;
	unsigned char	line_buf[1024];	// 大きめに。
	unsigned char 	work_buf[1024];
	unsigned char 	work_buf2[1024];
	unsigned char 	split1[1024];
	unsigned char 	split2[1024];

	int		ret;
	int		i;
	int		j;

	// ================================
	// 1行づつ HTTPヘッダを受信
	// ================================
	for (i=0;;i++)
	{
		// 1行受信 実行。
		memset(line_buf, '\0', sizeof(line_buf));
		recv_len = line_receive(accept_socket, line_buf, sizeof(line_buf));

		// debug. 受信したヘッダ表示
		debug_log_output("'%s'(%d byte)\n", line_buf, recv_len );

		// 受信した内容をチェック。
		if ( i != 0 && recv_len == 0 ) // 空行検知。ヘッダ受信終了。
		{
			break;
		}
		else if ( recv_len < 0 ) // 受信失敗
		{
			return ( -1 );
		}

		// --------------------------
		// GETメッセージチェック
		// --------------------------
		if ( i == 0 ) // 1行目のみチェック
		{
			debug_log_output("URI Check start.'%s'\n", line_buf);

			// GET/POSTある?
			if (strncmp(line_buf, "GET ", 4) && strncmp(line_buf, "POST ", 5))
			{
				debug_log_output("'GET' or 'POST' not found. error.");
				return ( -1 );
			}
			strncpy(http_recv_info_p->request_method, line_buf, sizeof(http_recv_info_p->request_method));
			cut_after_character(http_recv_info_p->request_method, ' ');

			// 最初のスペースまでを削除。
			cut_before_character(line_buf, ' ');

			// 次にスペースが出てきたところの後ろまでを削除。
			cut_after_character(line_buf, ' ');

			// ===========================
			// GETオプション部解析
			// ===========================

			// REQUEST_URI用・Proxy用に値を保存
			strncpy(http_recv_info_p->request_uri, line_buf, sizeof(http_recv_info_p->request_uri));

			// '?'が存在するかチェック。
			if ( strchr(line_buf, '?') != NULL )
			{

				strncpy(work_buf, line_buf, sizeof(work_buf));

				// '?'より前をカット
				cut_before_character(work_buf, '?' );
				debug_log_output("work_buf = '%s'", work_buf );

				while ( 1 )
				{
					memset(split1, '\0', sizeof(split1));
					memset(split2, '\0', sizeof(split2));

					uri_decode(split1, sizeof(split1), work_buf, sizeof(work_buf) );
					strcpy(work_buf, split1);

					// 最初に登場する'&'で分割
					ret = sentence_split(work_buf, '&', split1, split2 );
					if ( ret == 0 ) // 分割成功
					{
						strncpy(work_buf, split2, sizeof(work_buf));
					}
					else if (strlen(work_buf) > 0) // まだwork_bufに中身ある?
					{
						strncpy( split1, work_buf, sizeof(split1));
						strncpy( work_buf, "", sizeof(work_buf));
					}
					else // 処理終了
					{
						break;
					}

					// -------------------------------------
					// GETした内容 解析開始
					// 超安直。いいのかこんな比較で。
					// -------------------------------------

					// URIデコード
					// uri_decode(work_buf2, sizeof(work_buf2), split1, sizeof(split1) );
					strcpy(work_buf2, split1);

					// "page="あるか調査。
					if (strncasecmp( work_buf2, "page=", strlen("page=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');
						if ( strlen(work_buf2) > 0 )
						{
							// 構造体に値を保存。
							http_recv_info_p->page = atoi(work_buf2);
						}

						continue;
					}

					// "menupage="あるか調査。
					if (strncasecmp( work_buf2, "menupage=", strlen("menupage=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');
						if ( strlen(work_buf2) > 0 )
						{
							// 構造体に値を保存。
							http_recv_info_p->menupage = atoi(work_buf2);
						}

						continue;
					}

					// "title=" DVD title selection
					if (strncasecmp( work_buf2, "title=", strlen("title=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');
						if ( strlen(work_buf2) > 0 )
						{
							// 構造体に値を保存。
							http_recv_info_p->title = atoi(work_buf2);
						}

						continue;
					}

					if (strncasecmp( work_buf2, "width=", strlen("width=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');
						if ( strlen(work_buf2) > 0 )
						{
							// 構造体に値を保存。
							global_param.target_jpeg_width = atoi(work_buf2);
						}

						continue;
					}

					if (strncasecmp( work_buf2, "height=", strlen("height=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');
						if ( strlen(work_buf2) > 0 )
						{
							// 構造体に値を保存。
							global_param.target_jpeg_height = atoi(work_buf2);
						}

						continue;
					}

					// "action="あるか調査。
					if (strncasecmp( work_buf2, "action=", strlen("action=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');

						// 構造体に値を保存。
						strncpy(http_recv_info_p->action, work_buf2, sizeof(http_recv_info_p->action));
						continue;
					}

					// "type=" allplay list type
					if (strncasecmp( work_buf2, "type=movie", strlen("type=movie") ) == 0 )
					{
						http_recv_info_p->default_file_type = TYPE_MOVIE;
						continue;
					}
					if (strncasecmp( work_buf2, "type=music", strlen("type=music") ) == 0 )
					{
						http_recv_info_p->default_file_type = TYPE_MUSIC;
						continue;
					}
					if (strncasecmp( work_buf2, "type=photo", strlen("type=photo") ) == 0 )
					{
						http_recv_info_p->default_file_type = TYPE_JPEG;
						continue;
					}
					if (strncasecmp( work_buf2, "type=soundtrack", strlen("type=soundtrack") ) == 0 )
					{
						http_recv_info_p->default_file_type = TYPE_MUSICLIST;
						continue;
					}
					if (strncasecmp( work_buf2, "type=slideshow", strlen("type=slideshow") ) == 0 )
					{
						http_recv_info_p->default_file_type = TYPE_PLAYLIST;
						continue;
					}
					
					// "option="あるか調査
					if (strncasecmp( work_buf2, "option=", strlen("option=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');

						// 構造体に値を保存。
						strncpy(http_recv_info_p->option, work_buf2, sizeof(http_recv_info_p->option));
						continue;
					}

					// "alias="あるか調査
					if (strncasecmp( work_buf2, "alias=", strlen("alias=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');

						// 構造体に値を保存。
						strncpy(http_recv_info_p->alias, work_buf2, sizeof(http_recv_info_p->alias));

						if (strncasecmp(http_recv_info_p->alias, "movie", strlen("movie")) == 0)
							http_recv_info_p->default_file_type = TYPE_MOVIE;
						else if (strncasecmp(http_recv_info_p->alias, "music", strlen("music")) == 0)
							http_recv_info_p->default_file_type = TYPE_MUSIC;
						else if (strncasecmp(http_recv_info_p->alias, "photo", strlen("photo")) == 0)
							http_recv_info_p->default_file_type = TYPE_JPEG;
						else
							http_recv_info_p->default_file_type = TYPE_UNKNOWN;

						continue;
					}

					if (strncasecmp( work_buf2, "lsearch=", strlen("lsearch=") ) == 0 )
					{
						cut_before_character(work_buf2, '=');

						strcpy(http_recv_info_p->lsearch, work_buf2);
						strcpy(http_recv_info_p->recv_uri, work_buf2);
						continue;
					}

					// "search=
					if (strncasecmp( work_buf2, "search", strlen("search") ) == 0 )
					{
						if (strncasecmp(work_buf2, "search_movie", strlen("search_movie")) == 0) {
							http_recv_info_p->search_type = TYPE_MOVIE;
							strcpy(http_recv_info_p->search_str, "_movie");
							http_recv_info_p->default_file_type = TYPE_MOVIE;
							// printf("search movie for ");
						} else if (strncasecmp(work_buf2, "search_music", strlen("search_music")) == 0) {
							http_recv_info_p->search_type = TYPE_MUSIC;
							strcpy(http_recv_info_p->search_str, "_music");
							http_recv_info_p->default_file_type = TYPE_MUSIC;
							// printf("search music for ");
						} else if (strncasecmp(work_buf2, "search_photo", strlen("search_photo")) == 0) {
							http_recv_info_p->search_type = TYPE_JPEG;
							strcpy(http_recv_info_p->search_str, "_photo");
							http_recv_info_p->default_file_type = TYPE_JPEG;
							// printf("search photo for ");
						} else if (strncasecmp(work_buf2, "search_all", strlen("search_all")) == 0) {
							http_recv_info_p->search_type = TYPE_UNKNOWN;
							strcpy(http_recv_info_p->search_str, "_all");
							http_recv_info_p->default_file_type = TYPE_UNKNOWN;
							// printf("search all for ");
						} else
							continue;

						cut_before_character(work_buf2, '=');

						strncpy(http_recv_info_p->search, work_buf2, sizeof(http_recv_info_p->search));
						if (http_recv_info_p->search[0] == '\0')
							// everything qualifies
							strcpy(http_recv_info_p->search, ".*");

						// printf("%s\n", http_recv_info_p->search);
						continue;
					}

					// "sort="あるか調査
					if (strncasecmp( work_buf2, "sort=", strlen("sort=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');

						// 構造体に値を保存。
						strncpy(http_recv_info_p->sort, work_buf2, sizeof(http_recv_info_p->sort));
						continue;
					}


					// "dvdopt="あるか調査
					if (strncasecmp( work_buf2, "dvdopt=", strlen("dvdopt=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');

						// 構造体に値を保存。
						strncpy(http_recv_info_p->dvdopt, work_buf2, sizeof(http_recv_info_p->dvdopt));
						continue;
					}

					// "focus="あるか調査
					if (strncasecmp( work_buf2, "focus=", strlen("focus=") ) == 0 )
					{
						// = より前を削除
						cut_before_character(work_buf2, '=');

						// 構造体に値を保存。
						strncpy(http_recv_info_p->focus, work_buf2, sizeof(http_recv_info_p->focus));
						continue;
					}




				}
			}

			debug_log_output("http_recv_info_p->page = '%d'", http_recv_info_p->page);
			debug_log_output("http_recv_info_p->title = '%d'", http_recv_info_p->title);
			debug_log_output("http_recv_info_p->action = '%s'", http_recv_info_p->action);
			debug_log_output("http_recv_info_p->option = '%s'", http_recv_info_p->option);
			debug_log_output("http_recv_info_p->dvdopt = '%s'", http_recv_info_p->dvdopt);

			// URIデコード
			cut_after_character(line_buf, '?');
			uri_decode(work_buf, sizeof(work_buf), line_buf, sizeof(line_buf) );
			strncpy(line_buf, work_buf, sizeof(line_buf));
			debug_log_output("URI(decoded):'%s'\n", line_buf);

			convert_language_code(line_buf, work_buf, sizeof(work_buf), CODE_AUTO, CODE_EUC);
			debug_log_output("URI(decoded,euc,FYI):'%s'\n", work_buf);


			// 構造体に保存
			if (http_recv_info_p->lsearch[0] == '\0')
				strncpy(http_recv_info_p->recv_uri, line_buf, sizeof(http_recv_info_p->recv_uri));

			continue;

		}

		// User-agent切り出し
		if ( strncasecmp(line_buf, HTTP_USER_AGENT, strlen(HTTP_USER_AGENT) ) == 0 )
		{
			// ':'より前を切る
			cut_before_character(line_buf, ':');
			cut_first_character(line_buf, ' ');

			// 構造体に保存
			strncpy( http_recv_info_p->user_agent, line_buf, sizeof(http_recv_info_p->user_agent));

			// Set the skin name based on user agent, if desired
			for(j=0; j<global_param.alternate_skin_count; j++) {
				debug_log_output("Checking for '%s'", global_param.alternate_skin_match[j]);
				if(strstr(line_buf, global_param.alternate_skin_match[j]) != NULL) {
					strcpy(global_param.skin_name, global_param.alternate_skin_name[j]);
					debug_log_output("User agent matches alternate skin '%s'", global_param.skin_name); 
					break;
				}
			}
			continue;
		}

		// Rangeあるかチェック
		if ( strncasecmp(line_buf, HTTP_RANGE,	strlen(HTTP_RANGE) ) == 0 )
		{
			debug_log_output("%s Detect.\n", HTTP_RANGE);
			// ':' より前を切る。
			cut_before_character(line_buf, ':');
			cut_first_character(line_buf, ' ');

			// recv_range にRangeの中身保存
			strncpy(http_recv_info_p->recv_range, line_buf, sizeof(http_recv_info_p->recv_range));

			// '=' より前を切る
			cut_before_character(line_buf, '=');


			// '-'で前後に分割。
			sentence_split(line_buf, '-', work_buf, work_buf2);

			debug_log_output("work_buf='%s'\n", work_buf);
			debug_log_output("work_buf2='%s'\n", work_buf2);

			// 値を文字列→数値変換
			http_recv_info_p->range_start_pos  = strtoull(work_buf, NULL, 10);

			if ( strlen(work_buf2) > 0 )
			{
				http_recv_info_p->range_end_pos = strtoull(work_buf2, NULL, 10);
			}


			debug_log_output("range_start_pos=%d\n", http_recv_info_p->range_start_pos);
			debug_log_output("range_end_pos=%d\n", http_recv_info_p->range_end_pos);

			continue;
		}

		// Hostあるかチェック
		if ( strncasecmp(line_buf, HTTP_HOST,	strlen(HTTP_HOST) ) == 0 )
		{
			debug_log_output("%s Detect.\n", HTTP_HOST);
			// ':' より前を切る。
			cut_before_character(line_buf, ':');
			cut_first_character(line_buf, ' ');

			strncpy(http_recv_info_p->recv_host, line_buf, sizeof(http_recv_info_p->recv_host));
			if(NULL == strchr(http_recv_info_p->recv_host, ':')) {
				debug_log_output("CLIENT BUG: Host header field was missing port number - fixing");
				snprintf(http_recv_info_p->recv_host + strlen(http_recv_info_p->recv_host), sizeof(http_recv_info_p->recv_host)-1, ":%d", global_param.server_port);
				debug_log_output("%s '%s'", HTTP_HOST, http_recv_info_p->recv_host);
			}

			continue;
		}

		if (strncasecmp(line_buf, HTTP_AUTHORIZATION, strlen(HTTP_AUTHORIZATION)) == 0) {
			debug_log_output("%s Detect.\n", HTTP_AUTHORIZATION);
			// ':' より前を切る。
			cut_before_character(line_buf, ':');
			cut_first_character(line_buf, ' ');
			if (strncmp(line_buf, "Basic ", 6)) {
				debug_log_output("received '%s', is not supported.", line_buf);
				continue;
			}

			strncpy(http_recv_info_p->passwd, line_buf + 6, sizeof(http_recv_info_p->passwd));

			continue;
		}

		// Content-Lengthあるかチェック
		if ( strncasecmp(line_buf, HTTP_CONTENT_LENGTH_STR,	strlen(HTTP_CONTENT_LENGTH_STR) ) == 0 )
		{
			debug_log_output("%s Detect.\n", HTTP_CONTENT_LENGTH_STR);
			// ':' より前を切る。
			cut_before_character(line_buf, ':');
			cut_first_character(line_buf, ' ');
			/* recv_content_length は わざと long です. */
			http_recv_info_p->recv_content_length = strtol(line_buf, NULL, 10);
			debug_log_output("Content-Length: %ld", http_recv_info_p->recv_content_length);
			continue;
		}

	}

	return result;
}
Example #2
0
// **************************************************************************
// HTTPヘッダを受信して解析する。
//
// 処理するのはGETのみ。GET以外のメソッドが来たらエラー
// 今のところ、URIとuser_agent、Range、Hostを解析。
// URIは、URIデコードもやる。
//
//	return: 0 		正常終了
//	return: 0以外 	エラー
// **************************************************************************
static int http_header_receive(int accept_socket, HTTP_RECV_INFO *http_recv_info_p)
{
    int result = 0;
    int	recv_len;
    char	line_buf[1024];	// 大きめに。
    char 	work_buf[1024];
    char 	work_buf2[1024];
    char 	split1[1024];
    char 	split2[1024];
    int		ret;
    int		i;
    // ================================
    // 1行づつ HTTPヘッダを受信
    // ================================
    for (i=0;;i++){
        // 1行受信 実行。
        recv_len = line_receive(accept_socket, line_buf, sizeof(line_buf));
        // 受信した内容をチェック。
        if ( recv_len == 0 ){ // 空行検知。ヘッダ受信終了。
            break;
        }else if ( recv_len < 0 ){ // 受信失敗
            return ( -1 );
        }
        // debug. 受信したヘッダ表示
        debug_log_output("'%s'(%d byte)\n", line_buf, recv_len );
        // --------------------------
        // GETメッセージチェック
        // --------------------------
        if ( i == 0 ){ // 1行目のみチェック
            debug_log_output("%d:URI Check start.'%s'\n", accept_socket,line_buf);
            // GETある?
            if       ( strstr(line_buf, "GET") != NULL ){
                http_recv_info_p->isGet = 1;
            }else if ( strstr(line_buf, "HEAD") != NULL ){
                http_recv_info_p->isGet = 2;
            }else if ( strstr(line_buf, "POST") != NULL ){
                http_recv_info_p->isGet = 3;
            }else{
                debug_log_output("'GET' not found. error.%d",accept_socket);
                return ( -1 );
            }
            // 最初のスペースまでを削除。
            cut_before_character(line_buf, ' ');
            // 次にスペースが出てきたところの後ろまでを削除。
            cut_after_character(line_buf, ' ');
            // ===========================
            // GETオプション部解析
            // ===========================
            // REQUEST_URI用・Proxy用に値を保存
            strncpy(http_recv_info_p->request_uri, line_buf, sizeof(http_recv_info_p->request_uri));
            // '?'が存在するかチェック。
            if ( strchr(line_buf, '?') != NULL ){
                strncpy(work_buf, line_buf, sizeof(work_buf));
                // '?'より前をカット
                cut_before_character(work_buf, '?' );
                while ( 1 ){
                    memset(split1, 0, sizeof(split1));
                    memset(split2, 0, sizeof(split2));
                    // 最初に登場する'&'で分割
                    ret = sentence_split(work_buf, '&', split1, split2 );
                    if ( ret == 0 ){ // 分割成功
                        strncpy(work_buf, split2, sizeof(work_buf));
                    }else if (strlen(work_buf) > 0){ // まだwork_bufに中身ある?
                        strncpy( split1, work_buf, sizeof(split1));
                        strncpy( work_buf, "", sizeof(work_buf));
                    }else{ // 処理終了
                        break;
                    }
                    // -------------------------------------
                    // GETした内容 解析開始
                    // 超安直。いいのかこんな比較で。
                    // -------------------------------------
                    // URIデコード
                    uri_decode(work_buf2, sizeof(work_buf2), split1, sizeof(split1) );
                    // "action="あるか調査。
                    if (strncasecmp( work_buf2, "action=", strlen("action=") ) == 0 ){
                        // = より前を削除
                        cut_before_character(work_buf2, '=');
                        // 構造体に値を保存。
                        strncpy(http_recv_info_p->action, work_buf2, sizeof(http_recv_info_p->action));
                        continue;
                    }
                }
            }
            debug_log_output("http_recv_info_p->action = '%s'", http_recv_info_p->action);
            // URIデコード
            cut_after_character(line_buf, '?');
            uri_decode(work_buf, sizeof(work_buf), line_buf, sizeof(line_buf) );
            strncpy(line_buf, work_buf, sizeof(line_buf));
            debug_log_output("URI(decoded):'%s'\n", line_buf);
            convert_language_code(line_buf, work_buf, sizeof(work_buf), CODE_AUTO, CODE_EUC);
            debug_log_output("URI(decoded,euc,FYI):'%s'\n", work_buf);
            // 構造体に保存
            strncpy(http_recv_info_p->recv_uri, line_buf, sizeof(http_recv_info_p->recv_uri));
            //httpから始まってる場合には、http://以降の最初の'/'の前でカット
            if( strncmp(http_recv_info_p->recv_uri,"http://",7)==0){
                char* ptr = strstr(http_recv_info_p->recv_uri+7,"/");
                if( ptr ){
                    strcpy(http_recv_info_p->recv_uri,ptr);
                }
            }
            continue;
        }
        // User-agent切り出し
        if ( strncasecmp(line_buf, HTTP_USER_AGENT, strlen(HTTP_USER_AGENT) ) == 0 ){
            debug_log_output("User-agent: Detect.\n");
            // ':'より前を切る
            cut_before_character(line_buf, ':');
            cut_first_character(line_buf, ' ');
            // 構造体に保存
            strncpy( http_recv_info_p->user_agent, line_buf, sizeof(http_recv_info_p->user_agent));
            continue;
        }
        // Rangeあるかチェック
        if ( strncasecmp(line_buf, HTTP_RANGE,	strlen(HTTP_RANGE) ) == 0 ){
            debug_log_output("%s Detect.\n", HTTP_RANGE);
            // ':' より前を切る。
            cut_before_character(line_buf, ':');
            cut_first_character(line_buf, ' ');
            // recv_range にRangeの中身保存
            strncpy(http_recv_info_p->recv_range, line_buf, sizeof(http_recv_info_p->recv_range));
            // '=' より前を切る
            cut_before_character(line_buf, '=');
            // '-'で前後に分割。
            sentence_split(line_buf, '-', work_buf, work_buf2);
            debug_log_output("wrok_buf='%s'\n", work_buf);
            debug_log_output("wrok_buf2='%s'\n", work_buf2);
            // 値を文字列→数値変換
            http_recv_info_p->range_start_pos  = strtoull(work_buf, NULL, 10);
            if ( strlen(work_buf2) > 0 ){
                http_recv_info_p->range_end_pos = strtoull(work_buf2, NULL, 10);
            }
            debug_log_output("range_start_pos=%d\n", http_recv_info_p->range_start_pos);
            debug_log_output("range_end_pos=%d\n", http_recv_info_p->range_end_pos);
            continue;
        }
        // Hostあるかチェック
        if ( strncasecmp(line_buf, HTTP_HOST,	strlen(HTTP_HOST) ) == 0 ){
            // ':' より前を切る。
            cut_before_character(line_buf, ':');
            cut_first_character(line_buf, ' ');
            strncpy(http_recv_info_p->recv_host, line_buf, sizeof(http_recv_info_p->recv_host));
            debug_log_output("%s Detect. %s '%s'", HTTP_HOST, HTTP_HOST, http_recv_info_p->recv_host);
            continue;
        }
        // Content-Lengthあるかチェック
        if ( strncasecmp(line_buf, HTTP_CONTENT_LENGTH1, strlen(HTTP_CONTENT_LENGTH1) ) == 0 ){
            // ':' より前を切る。
            cut_before_character(line_buf, ':');
            cut_first_character(line_buf, ' ');
            strncpy(http_recv_info_p->content_length, line_buf, sizeof(http_recv_info_p->content_length));
            debug_log_output("%s Detect. %s '%s'", HTTP_CONTENT_LENGTH1, HTTP_CONTENT_LENGTH1, http_recv_info_p->content_length);
            continue;
        }
        // Content-TYPEあるかチェック
        if ( strncasecmp(line_buf, HTTP_CONTENT_TYPE1, strlen(HTTP_CONTENT_TYPE1) ) == 0 ){
            // ':' より前を切る。
            cut_before_character(line_buf, ':');
            cut_first_character(line_buf, ' ');
            strncpy(http_recv_info_p->content_type, line_buf, sizeof(http_recv_info_p->content_type));
            debug_log_output("%s Detect. %s '%s'", HTTP_CONTENT_TYPE1, HTTP_CONTENT_TYPE1, http_recv_info_p->content_type);
            continue;
        }
    }
    return result;
}